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(),
16524 return Roo.Markdown.marked(text);
16529 // Wraps all "globals" so that the only thing
16530 // exposed is makeHtml().
16535 * Block-Level Grammar
16540 code: /^( {4}[^\n]+\n*)+/,
16542 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16543 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16545 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16546 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16547 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16548 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16549 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16551 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16555 block.bullet = /(?:[*+-]|\d+\.)/;
16556 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16557 block.item = replace(block.item, 'gm')
16558 (/bull/g, block.bullet)
16561 block.list = replace(block.list)
16562 (/bull/g, block.bullet)
16563 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16564 ('def', '\\n+(?=' + block.def.source + ')')
16567 block.blockquote = replace(block.blockquote)
16571 block._tag = '(?!(?:'
16572 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16573 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16574 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16576 block.html = replace(block.html)
16577 ('comment', /<!--[\s\S]*?-->/)
16578 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16579 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16580 (/tag/g, block._tag)
16583 block.paragraph = replace(block.paragraph)
16585 ('heading', block.heading)
16586 ('lheading', block.lheading)
16587 ('blockquote', block.blockquote)
16588 ('tag', '<' + block._tag)
16593 * Normal Block Grammar
16596 block.normal = merge({}, block);
16599 * GFM Block Grammar
16602 block.gfm = merge({}, block.normal, {
16603 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16605 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16608 block.gfm.paragraph = replace(block.paragraph)
16610 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16611 + block.list.source.replace('\\1', '\\3') + '|')
16615 * GFM + Tables Block Grammar
16618 block.tables = merge({}, block.gfm, {
16619 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16620 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16627 function Lexer(options) {
16629 this.tokens.links = {};
16630 this.options = options || marked.defaults;
16631 this.rules = block.normal;
16633 if (this.options.gfm) {
16634 if (this.options.tables) {
16635 this.rules = block.tables;
16637 this.rules = block.gfm;
16643 * Expose Block Rules
16646 Lexer.rules = block;
16649 * Static Lex Method
16652 Lexer.lex = function(src, options) {
16653 var lexer = new Lexer(options);
16654 return lexer.lex(src);
16661 Lexer.prototype.lex = function(src) {
16663 .replace(/\r\n|\r/g, '\n')
16664 .replace(/\t/g, ' ')
16665 .replace(/\u00a0/g, ' ')
16666 .replace(/\u2424/g, '\n');
16668 return this.token(src, true);
16675 Lexer.prototype.token = function(src, top, bq) {
16676 var src = src.replace(/^ +$/gm, '')
16689 if (cap = this.rules.newline.exec(src)) {
16690 src = src.substring(cap[0].length);
16691 if (cap[0].length > 1) {
16699 if (cap = this.rules.code.exec(src)) {
16700 src = src.substring(cap[0].length);
16701 cap = cap[0].replace(/^ {4}/gm, '');
16704 text: !this.options.pedantic
16705 ? cap.replace(/\n+$/, '')
16712 if (cap = this.rules.fences.exec(src)) {
16713 src = src.substring(cap[0].length);
16723 if (cap = this.rules.heading.exec(src)) {
16724 src = src.substring(cap[0].length);
16727 depth: cap[1].length,
16733 // table no leading pipe (gfm)
16734 if (top && (cap = this.rules.nptable.exec(src))) {
16735 src = src.substring(cap[0].length);
16739 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16740 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16741 cells: cap[3].replace(/\n$/, '').split('\n')
16744 for (i = 0; i < item.align.length; i++) {
16745 if (/^ *-+: *$/.test(item.align[i])) {
16746 item.align[i] = 'right';
16747 } else if (/^ *:-+: *$/.test(item.align[i])) {
16748 item.align[i] = 'center';
16749 } else if (/^ *:-+ *$/.test(item.align[i])) {
16750 item.align[i] = 'left';
16752 item.align[i] = null;
16756 for (i = 0; i < item.cells.length; i++) {
16757 item.cells[i] = item.cells[i].split(/ *\| */);
16760 this.tokens.push(item);
16766 if (cap = this.rules.lheading.exec(src)) {
16767 src = src.substring(cap[0].length);
16770 depth: cap[2] === '=' ? 1 : 2,
16777 if (cap = this.rules.hr.exec(src)) {
16778 src = src.substring(cap[0].length);
16786 if (cap = this.rules.blockquote.exec(src)) {
16787 src = src.substring(cap[0].length);
16790 type: 'blockquote_start'
16793 cap = cap[0].replace(/^ *> ?/gm, '');
16795 // Pass `top` to keep the current
16796 // "toplevel" state. This is exactly
16797 // how markdown.pl works.
16798 this.token(cap, top, true);
16801 type: 'blockquote_end'
16808 if (cap = this.rules.list.exec(src)) {
16809 src = src.substring(cap[0].length);
16813 type: 'list_start',
16814 ordered: bull.length > 1
16817 // Get each top-level item.
16818 cap = cap[0].match(this.rules.item);
16824 for (; i < l; i++) {
16827 // Remove the list item's bullet
16828 // so it is seen as the next token.
16829 space = item.length;
16830 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16832 // Outdent whatever the
16833 // list item contains. Hacky.
16834 if (~item.indexOf('\n ')) {
16835 space -= item.length;
16836 item = !this.options.pedantic
16837 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16838 : item.replace(/^ {1,4}/gm, '');
16841 // Determine whether the next list item belongs here.
16842 // Backpedal if it does not belong in this list.
16843 if (this.options.smartLists && i !== l - 1) {
16844 b = block.bullet.exec(cap[i + 1])[0];
16845 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16846 src = cap.slice(i + 1).join('\n') + src;
16851 // Determine whether item is loose or not.
16852 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16853 // for discount behavior.
16854 loose = next || /\n\n(?!\s*$)/.test(item);
16856 next = item.charAt(item.length - 1) === '\n';
16857 if (!loose) { loose = next; }
16862 ? 'loose_item_start'
16863 : 'list_item_start'
16867 this.token(item, false, bq);
16870 type: 'list_item_end'
16882 if (cap = this.rules.html.exec(src)) {
16883 src = src.substring(cap[0].length);
16885 type: this.options.sanitize
16888 pre: !this.options.sanitizer
16889 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
16896 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
16897 src = src.substring(cap[0].length);
16898 this.tokens.links[cap[1].toLowerCase()] = {
16906 if (top && (cap = this.rules.table.exec(src))) {
16907 src = src.substring(cap[0].length);
16911 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16912 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16913 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
16916 for (i = 0; i < item.align.length; i++) {
16917 if (/^ *-+: *$/.test(item.align[i])) {
16918 item.align[i] = 'right';
16919 } else if (/^ *:-+: *$/.test(item.align[i])) {
16920 item.align[i] = 'center';
16921 } else if (/^ *:-+ *$/.test(item.align[i])) {
16922 item.align[i] = 'left';
16924 item.align[i] = null;
16928 for (i = 0; i < item.cells.length; i++) {
16929 item.cells[i] = item.cells[i]
16930 .replace(/^ *\| *| *\| *$/g, '')
16934 this.tokens.push(item);
16939 // top-level paragraph
16940 if (top && (cap = this.rules.paragraph.exec(src))) {
16941 src = src.substring(cap[0].length);
16944 text: cap[1].charAt(cap[1].length - 1) === '\n'
16945 ? cap[1].slice(0, -1)
16952 if (cap = this.rules.text.exec(src)) {
16953 // Top-level should never reach here.
16954 src = src.substring(cap[0].length);
16964 Error('Infinite loop on byte: ' + src.charCodeAt(0));
16968 return this.tokens;
16972 * Inline-Level Grammar
16976 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
16977 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
16979 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
16980 link: /^!?\[(inside)\]\(href\)/,
16981 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
16982 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
16983 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
16984 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
16985 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
16986 br: /^ {2,}\n(?!\s*$)/,
16988 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
16991 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
16992 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
16994 inline.link = replace(inline.link)
16995 ('inside', inline._inside)
16996 ('href', inline._href)
16999 inline.reflink = replace(inline.reflink)
17000 ('inside', inline._inside)
17004 * Normal Inline Grammar
17007 inline.normal = merge({}, inline);
17010 * Pedantic Inline Grammar
17013 inline.pedantic = merge({}, inline.normal, {
17014 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17015 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17019 * GFM Inline Grammar
17022 inline.gfm = merge({}, inline.normal, {
17023 escape: replace(inline.escape)('])', '~|])')(),
17024 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17025 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17026 text: replace(inline.text)
17028 ('|', '|https?://|')
17033 * GFM + Line Breaks Inline Grammar
17036 inline.breaks = merge({}, inline.gfm, {
17037 br: replace(inline.br)('{2,}', '*')(),
17038 text: replace(inline.gfm.text)('{2,}', '*')()
17042 * Inline Lexer & Compiler
17045 function InlineLexer(links, options) {
17046 this.options = options || marked.defaults;
17047 this.links = links;
17048 this.rules = inline.normal;
17049 this.renderer = this.options.renderer || new Renderer;
17050 this.renderer.options = this.options;
17054 Error('Tokens array requires a `links` property.');
17057 if (this.options.gfm) {
17058 if (this.options.breaks) {
17059 this.rules = inline.breaks;
17061 this.rules = inline.gfm;
17063 } else if (this.options.pedantic) {
17064 this.rules = inline.pedantic;
17069 * Expose Inline Rules
17072 InlineLexer.rules = inline;
17075 * Static Lexing/Compiling Method
17078 InlineLexer.output = function(src, links, options) {
17079 var inline = new InlineLexer(links, options);
17080 return inline.output(src);
17087 InlineLexer.prototype.output = function(src) {
17096 if (cap = this.rules.escape.exec(src)) {
17097 src = src.substring(cap[0].length);
17103 if (cap = this.rules.autolink.exec(src)) {
17104 src = src.substring(cap[0].length);
17105 if (cap[2] === '@') {
17106 text = cap[1].charAt(6) === ':'
17107 ? this.mangle(cap[1].substring(7))
17108 : this.mangle(cap[1]);
17109 href = this.mangle('mailto:') + text;
17111 text = escape(cap[1]);
17114 out += this.renderer.link(href, null, text);
17119 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17120 src = src.substring(cap[0].length);
17121 text = escape(cap[1]);
17123 out += this.renderer.link(href, null, text);
17128 if (cap = this.rules.tag.exec(src)) {
17129 if (!this.inLink && /^<a /i.test(cap[0])) {
17130 this.inLink = true;
17131 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17132 this.inLink = false;
17134 src = src.substring(cap[0].length);
17135 out += this.options.sanitize
17136 ? this.options.sanitizer
17137 ? this.options.sanitizer(cap[0])
17144 if (cap = this.rules.link.exec(src)) {
17145 src = src.substring(cap[0].length);
17146 this.inLink = true;
17147 out += this.outputLink(cap, {
17151 this.inLink = false;
17156 if ((cap = this.rules.reflink.exec(src))
17157 || (cap = this.rules.nolink.exec(src))) {
17158 src = src.substring(cap[0].length);
17159 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17160 link = this.links[link.toLowerCase()];
17161 if (!link || !link.href) {
17162 out += cap[0].charAt(0);
17163 src = cap[0].substring(1) + src;
17166 this.inLink = true;
17167 out += this.outputLink(cap, link);
17168 this.inLink = false;
17173 if (cap = this.rules.strong.exec(src)) {
17174 src = src.substring(cap[0].length);
17175 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17180 if (cap = this.rules.em.exec(src)) {
17181 src = src.substring(cap[0].length);
17182 out += this.renderer.em(this.output(cap[2] || cap[1]));
17187 if (cap = this.rules.code.exec(src)) {
17188 src = src.substring(cap[0].length);
17189 out += this.renderer.codespan(escape(cap[2], true));
17194 if (cap = this.rules.br.exec(src)) {
17195 src = src.substring(cap[0].length);
17196 out += this.renderer.br();
17201 if (cap = this.rules.del.exec(src)) {
17202 src = src.substring(cap[0].length);
17203 out += this.renderer.del(this.output(cap[1]));
17208 if (cap = this.rules.text.exec(src)) {
17209 src = src.substring(cap[0].length);
17210 out += this.renderer.text(escape(this.smartypants(cap[0])));
17216 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17227 InlineLexer.prototype.outputLink = function(cap, link) {
17228 var href = escape(link.href)
17229 , title = link.title ? escape(link.title) : null;
17231 return cap[0].charAt(0) !== '!'
17232 ? this.renderer.link(href, title, this.output(cap[1]))
17233 : this.renderer.image(href, title, escape(cap[1]));
17237 * Smartypants Transformations
17240 InlineLexer.prototype.smartypants = function(text) {
17241 if (!this.options.smartypants) { return text; }
17244 .replace(/---/g, '\u2014')
17246 .replace(/--/g, '\u2013')
17248 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17249 // closing singles & apostrophes
17250 .replace(/'/g, '\u2019')
17252 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17254 .replace(/"/g, '\u201d')
17256 .replace(/\.{3}/g, '\u2026');
17263 InlineLexer.prototype.mangle = function(text) {
17264 if (!this.options.mangle) { return text; }
17270 for (; i < l; i++) {
17271 ch = text.charCodeAt(i);
17272 if (Math.random() > 0.5) {
17273 ch = 'x' + ch.toString(16);
17275 out += '&#' + ch + ';';
17285 function Renderer(options) {
17286 this.options = options || {};
17289 Renderer.prototype.code = function(code, lang, escaped) {
17290 if (this.options.highlight) {
17291 var out = this.options.highlight(code, lang);
17292 if (out != null && out !== code) {
17297 // hack!!! - it's already escapeD?
17302 return '<pre><code>'
17303 + (escaped ? code : escape(code, true))
17304 + '\n</code></pre>';
17307 return '<pre><code class="'
17308 + this.options.langPrefix
17309 + escape(lang, true)
17311 + (escaped ? code : escape(code, true))
17312 + '\n</code></pre>\n';
17315 Renderer.prototype.blockquote = function(quote) {
17316 return '<blockquote>\n' + quote + '</blockquote>\n';
17319 Renderer.prototype.html = function(html) {
17323 Renderer.prototype.heading = function(text, level, raw) {
17327 + this.options.headerPrefix
17328 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17336 Renderer.prototype.hr = function() {
17337 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17340 Renderer.prototype.list = function(body, ordered) {
17341 var type = ordered ? 'ol' : 'ul';
17342 return '<' + type + '>\n' + body + '</' + type + '>\n';
17345 Renderer.prototype.listitem = function(text) {
17346 return '<li>' + text + '</li>\n';
17349 Renderer.prototype.paragraph = function(text) {
17350 return '<p>' + text + '</p>\n';
17353 Renderer.prototype.table = function(header, body) {
17364 Renderer.prototype.tablerow = function(content) {
17365 return '<tr>\n' + content + '</tr>\n';
17368 Renderer.prototype.tablecell = function(content, flags) {
17369 var type = flags.header ? 'th' : 'td';
17370 var tag = flags.align
17371 ? '<' + type + ' style="text-align:' + flags.align + '">'
17372 : '<' + type + '>';
17373 return tag + content + '</' + type + '>\n';
17376 // span level renderer
17377 Renderer.prototype.strong = function(text) {
17378 return '<strong>' + text + '</strong>';
17381 Renderer.prototype.em = function(text) {
17382 return '<em>' + text + '</em>';
17385 Renderer.prototype.codespan = function(text) {
17386 return '<code>' + text + '</code>';
17389 Renderer.prototype.br = function() {
17390 return this.options.xhtml ? '<br/>' : '<br>';
17393 Renderer.prototype.del = function(text) {
17394 return '<del>' + text + '</del>';
17397 Renderer.prototype.link = function(href, title, text) {
17398 if (this.options.sanitize) {
17400 var prot = decodeURIComponent(unescape(href))
17401 .replace(/[^\w:]/g, '')
17406 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17410 var out = '<a href="' + href + '"';
17412 out += ' title="' + title + '"';
17414 out += '>' + text + '</a>';
17418 Renderer.prototype.image = function(href, title, text) {
17419 var out = '<img src="' + href + '" alt="' + text + '"';
17421 out += ' title="' + title + '"';
17423 out += this.options.xhtml ? '/>' : '>';
17427 Renderer.prototype.text = function(text) {
17432 * Parsing & Compiling
17435 function Parser(options) {
17438 this.options = options || marked.defaults;
17439 this.options.renderer = this.options.renderer || new Renderer;
17440 this.renderer = this.options.renderer;
17441 this.renderer.options = this.options;
17445 * Static Parse Method
17448 Parser.parse = function(src, options, renderer) {
17449 var parser = new Parser(options, renderer);
17450 return parser.parse(src);
17457 Parser.prototype.parse = function(src) {
17458 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17459 this.tokens = src.reverse();
17462 while (this.next()) {
17473 Parser.prototype.next = function() {
17474 return this.token = this.tokens.pop();
17478 * Preview Next Token
17481 Parser.prototype.peek = function() {
17482 return this.tokens[this.tokens.length - 1] || 0;
17486 * Parse Text Tokens
17489 Parser.prototype.parseText = function() {
17490 var body = this.token.text;
17492 while (this.peek().type === 'text') {
17493 body += '\n' + this.next().text;
17496 return this.inline.output(body);
17500 * Parse Current Token
17503 Parser.prototype.tok = function() {
17504 switch (this.token.type) {
17509 return this.renderer.hr();
17512 return this.renderer.heading(
17513 this.inline.output(this.token.text),
17518 return this.renderer.code(this.token.text,
17520 this.token.escaped);
17533 for (i = 0; i < this.token.header.length; i++) {
17534 flags = { header: true, align: this.token.align[i] };
17535 cell += this.renderer.tablecell(
17536 this.inline.output(this.token.header[i]),
17537 { header: true, align: this.token.align[i] }
17540 header += this.renderer.tablerow(cell);
17542 for (i = 0; i < this.token.cells.length; i++) {
17543 row = this.token.cells[i];
17546 for (j = 0; j < row.length; j++) {
17547 cell += this.renderer.tablecell(
17548 this.inline.output(row[j]),
17549 { header: false, align: this.token.align[j] }
17553 body += this.renderer.tablerow(cell);
17555 return this.renderer.table(header, body);
17557 case 'blockquote_start': {
17560 while (this.next().type !== 'blockquote_end') {
17561 body += this.tok();
17564 return this.renderer.blockquote(body);
17566 case 'list_start': {
17568 , ordered = this.token.ordered;
17570 while (this.next().type !== 'list_end') {
17571 body += this.tok();
17574 return this.renderer.list(body, ordered);
17576 case 'list_item_start': {
17579 while (this.next().type !== 'list_item_end') {
17580 body += this.token.type === 'text'
17585 return this.renderer.listitem(body);
17587 case 'loose_item_start': {
17590 while (this.next().type !== 'list_item_end') {
17591 body += this.tok();
17594 return this.renderer.listitem(body);
17597 var html = !this.token.pre && !this.options.pedantic
17598 ? this.inline.output(this.token.text)
17600 return this.renderer.html(html);
17602 case 'paragraph': {
17603 return this.renderer.paragraph(this.inline.output(this.token.text));
17606 return this.renderer.paragraph(this.parseText());
17615 function escape(html, encode) {
17617 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17618 .replace(/</g, '<')
17619 .replace(/>/g, '>')
17620 .replace(/"/g, '"')
17621 .replace(/'/g, ''');
17624 function unescape(html) {
17625 // explicitly match decimal, hex, and named HTML entities
17626 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17627 n = n.toLowerCase();
17628 if (n === 'colon') { return ':'; }
17629 if (n.charAt(0) === '#') {
17630 return n.charAt(1) === 'x'
17631 ? String.fromCharCode(parseInt(n.substring(2), 16))
17632 : String.fromCharCode(+n.substring(1));
17638 function replace(regex, opt) {
17639 regex = regex.source;
17641 return function self(name, val) {
17642 if (!name) { return new RegExp(regex, opt); }
17643 val = val.source || val;
17644 val = val.replace(/(^|[^\[])\^/g, '$1');
17645 regex = regex.replace(name, val);
17653 function merge(obj) {
17658 for (; i < arguments.length; i++) {
17659 target = arguments[i];
17660 for (key in target) {
17661 if (Object.prototype.hasOwnProperty.call(target, key)) {
17662 obj[key] = target[key];
17675 function marked(src, opt, callback) {
17676 if (callback || typeof opt === 'function') {
17682 opt = merge({}, marked.defaults, opt || {});
17684 var highlight = opt.highlight
17690 tokens = Lexer.lex(src, opt)
17692 return callback(e);
17695 pending = tokens.length;
17697 var done = function(err) {
17699 opt.highlight = highlight;
17700 return callback(err);
17706 out = Parser.parse(tokens, opt);
17711 opt.highlight = highlight;
17715 : callback(null, out);
17718 if (!highlight || highlight.length < 3) {
17722 delete opt.highlight;
17724 if (!pending) { return done(); }
17726 for (; i < tokens.length; i++) {
17728 if (token.type !== 'code') {
17729 return --pending || done();
17731 return highlight(token.text, token.lang, function(err, code) {
17732 if (err) { return done(err); }
17733 if (code == null || code === token.text) {
17734 return --pending || done();
17737 token.escaped = true;
17738 --pending || done();
17746 if (opt) { opt = merge({}, marked.defaults, opt); }
17747 return Parser.parse(Lexer.lex(src, opt), opt);
17749 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17750 if ((opt || marked.defaults).silent) {
17751 return '<p>An error occured:</p><pre>'
17752 + escape(e.message + '', true)
17764 marked.setOptions = function(opt) {
17765 merge(marked.defaults, opt);
17769 marked.defaults = {
17780 langPrefix: 'lang-',
17781 smartypants: false,
17783 renderer: new Renderer,
17791 marked.Parser = Parser;
17792 marked.parser = Parser.parse;
17794 marked.Renderer = Renderer;
17796 marked.Lexer = Lexer;
17797 marked.lexer = Lexer.lex;
17799 marked.InlineLexer = InlineLexer;
17800 marked.inlineLexer = InlineLexer.output;
17802 marked.parse = marked;
17804 Roo.Markdown.marked = marked;
17808 * Ext JS Library 1.1.1
17809 * Copyright(c) 2006-2007, Ext JS, LLC.
17811 * Originally Released Under LGPL - original licence link has changed is not relivant.
17814 * <script type="text/javascript">
17820 * These classes are derivatives of the similarly named classes in the YUI Library.
17821 * The original license:
17822 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17823 * Code licensed under the BSD License:
17824 * http://developer.yahoo.net/yui/license.txt
17829 var Event=Roo.EventManager;
17830 var Dom=Roo.lib.Dom;
17833 * @class Roo.dd.DragDrop
17834 * @extends Roo.util.Observable
17835 * Defines the interface and base operation of items that that can be
17836 * dragged or can be drop targets. It was designed to be extended, overriding
17837 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17838 * Up to three html elements can be associated with a DragDrop instance:
17840 * <li>linked element: the element that is passed into the constructor.
17841 * This is the element which defines the boundaries for interaction with
17842 * other DragDrop objects.</li>
17843 * <li>handle element(s): The drag operation only occurs if the element that
17844 * was clicked matches a handle element. By default this is the linked
17845 * element, but there are times that you will want only a portion of the
17846 * linked element to initiate the drag operation, and the setHandleElId()
17847 * method provides a way to define this.</li>
17848 * <li>drag element: this represents the element that would be moved along
17849 * with the cursor during a drag operation. By default, this is the linked
17850 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17851 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17854 * This class should not be instantiated until the onload event to ensure that
17855 * the associated elements are available.
17856 * The following would define a DragDrop obj that would interact with any
17857 * other DragDrop obj in the "group1" group:
17859 * dd = new Roo.dd.DragDrop("div1", "group1");
17861 * Since none of the event handlers have been implemented, nothing would
17862 * actually happen if you were to run the code above. Normally you would
17863 * override this class or one of the default implementations, but you can
17864 * also override the methods you want on an instance of the class...
17866 * dd.onDragDrop = function(e, id) {
17867 * alert("dd was dropped on " + id);
17871 * @param {String} id of the element that is linked to this instance
17872 * @param {String} sGroup the group of related DragDrop objects
17873 * @param {object} config an object containing configurable attributes
17874 * Valid properties for DragDrop:
17875 * padding, isTarget, maintainOffset, primaryButtonOnly
17877 Roo.dd.DragDrop = function(id, sGroup, config) {
17879 this.init(id, sGroup, config);
17884 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17887 * The id of the element associated with this object. This is what we
17888 * refer to as the "linked element" because the size and position of
17889 * this element is used to determine when the drag and drop objects have
17897 * Configuration attributes passed into the constructor
17904 * The id of the element that will be dragged. By default this is same
17905 * as the linked element , but could be changed to another element. Ex:
17907 * @property dragElId
17914 * the id of the element that initiates the drag operation. By default
17915 * this is the linked element, but could be changed to be a child of this
17916 * element. This lets us do things like only starting the drag when the
17917 * header element within the linked html element is clicked.
17918 * @property handleElId
17925 * An associative array of HTML tags that will be ignored if clicked.
17926 * @property invalidHandleTypes
17927 * @type {string: string}
17929 invalidHandleTypes: null,
17932 * An associative array of ids for elements that will be ignored if clicked
17933 * @property invalidHandleIds
17934 * @type {string: string}
17936 invalidHandleIds: null,
17939 * An indexted array of css class names for elements that will be ignored
17941 * @property invalidHandleClasses
17944 invalidHandleClasses: null,
17947 * The linked element's absolute X position at the time the drag was
17949 * @property startPageX
17956 * The linked element's absolute X position at the time the drag was
17958 * @property startPageY
17965 * The group defines a logical collection of DragDrop objects that are
17966 * related. Instances only get events when interacting with other
17967 * DragDrop object in the same group. This lets us define multiple
17968 * groups using a single DragDrop subclass if we want.
17970 * @type {string: string}
17975 * Individual drag/drop instances can be locked. This will prevent
17976 * onmousedown start drag.
17984 * Lock this instance
17987 lock: function() { this.locked = true; },
17990 * Unlock this instace
17993 unlock: function() { this.locked = false; },
17996 * By default, all insances can be a drop target. This can be disabled by
17997 * setting isTarget to false.
18004 * The padding configured for this drag and drop object for calculating
18005 * the drop zone intersection with this object.
18012 * Cached reference to the linked element
18013 * @property _domRef
18019 * Internal typeof flag
18020 * @property __ygDragDrop
18023 __ygDragDrop: true,
18026 * Set to true when horizontal contraints are applied
18027 * @property constrainX
18034 * Set to true when vertical contraints are applied
18035 * @property constrainY
18042 * The left constraint
18050 * The right constraint
18058 * The up constraint
18067 * The down constraint
18075 * Maintain offsets when we resetconstraints. Set to true when you want
18076 * the position of the element relative to its parent to stay the same
18077 * when the page changes
18079 * @property maintainOffset
18082 maintainOffset: false,
18085 * Array of pixel locations the element will snap to if we specified a
18086 * horizontal graduation/interval. This array is generated automatically
18087 * when you define a tick interval.
18094 * Array of pixel locations the element will snap to if we specified a
18095 * vertical graduation/interval. This array is generated automatically
18096 * when you define a tick interval.
18103 * By default the drag and drop instance will only respond to the primary
18104 * button click (left button for a right-handed mouse). Set to true to
18105 * allow drag and drop to start with any mouse click that is propogated
18107 * @property primaryButtonOnly
18110 primaryButtonOnly: true,
18113 * The availabe property is false until the linked dom element is accessible.
18114 * @property available
18120 * By default, drags can only be initiated if the mousedown occurs in the
18121 * region the linked element is. This is done in part to work around a
18122 * bug in some browsers that mis-report the mousedown if the previous
18123 * mouseup happened outside of the window. This property is set to true
18124 * if outer handles are defined.
18126 * @property hasOuterHandles
18130 hasOuterHandles: false,
18133 * Code that executes immediately before the startDrag event
18134 * @method b4StartDrag
18137 b4StartDrag: function(x, y) { },
18140 * Abstract method called after a drag/drop object is clicked
18141 * and the drag or mousedown time thresholds have beeen met.
18142 * @method startDrag
18143 * @param {int} X click location
18144 * @param {int} Y click location
18146 startDrag: function(x, y) { /* override this */ },
18149 * Code that executes immediately before the onDrag event
18153 b4Drag: function(e) { },
18156 * Abstract method called during the onMouseMove event while dragging an
18159 * @param {Event} e the mousemove event
18161 onDrag: function(e) { /* override this */ },
18164 * Abstract method called when this element fist begins hovering over
18165 * another DragDrop obj
18166 * @method onDragEnter
18167 * @param {Event} e the mousemove event
18168 * @param {String|DragDrop[]} id In POINT mode, the element
18169 * id this is hovering over. In INTERSECT mode, an array of one or more
18170 * dragdrop items being hovered over.
18172 onDragEnter: function(e, id) { /* override this */ },
18175 * Code that executes immediately before the onDragOver event
18176 * @method b4DragOver
18179 b4DragOver: function(e) { },
18182 * Abstract method called when this element is hovering over another
18184 * @method onDragOver
18185 * @param {Event} e the mousemove event
18186 * @param {String|DragDrop[]} id In POINT mode, the element
18187 * id this is hovering over. In INTERSECT mode, an array of dd items
18188 * being hovered over.
18190 onDragOver: function(e, id) { /* override this */ },
18193 * Code that executes immediately before the onDragOut event
18194 * @method b4DragOut
18197 b4DragOut: function(e) { },
18200 * Abstract method called when we are no longer hovering over an element
18201 * @method onDragOut
18202 * @param {Event} e the mousemove event
18203 * @param {String|DragDrop[]} id In POINT mode, the element
18204 * id this was hovering over. In INTERSECT mode, an array of dd items
18205 * that the mouse is no longer over.
18207 onDragOut: function(e, id) { /* override this */ },
18210 * Code that executes immediately before the onDragDrop event
18211 * @method b4DragDrop
18214 b4DragDrop: function(e) { },
18217 * Abstract method called when this item is dropped on another DragDrop
18219 * @method onDragDrop
18220 * @param {Event} e the mouseup event
18221 * @param {String|DragDrop[]} id In POINT mode, the element
18222 * id this was dropped on. In INTERSECT mode, an array of dd items this
18225 onDragDrop: function(e, id) { /* override this */ },
18228 * Abstract method called when this item is dropped on an area with no
18230 * @method onInvalidDrop
18231 * @param {Event} e the mouseup event
18233 onInvalidDrop: function(e) { /* override this */ },
18236 * Code that executes immediately before the endDrag event
18237 * @method b4EndDrag
18240 b4EndDrag: function(e) { },
18243 * Fired when we are done dragging the object
18245 * @param {Event} e the mouseup event
18247 endDrag: function(e) { /* override this */ },
18250 * Code executed immediately before the onMouseDown event
18251 * @method b4MouseDown
18252 * @param {Event} e the mousedown event
18255 b4MouseDown: function(e) { },
18258 * Event handler that fires when a drag/drop obj gets a mousedown
18259 * @method onMouseDown
18260 * @param {Event} e the mousedown event
18262 onMouseDown: function(e) { /* override this */ },
18265 * Event handler that fires when a drag/drop obj gets a mouseup
18266 * @method onMouseUp
18267 * @param {Event} e the mouseup event
18269 onMouseUp: function(e) { /* override this */ },
18272 * Override the onAvailable method to do what is needed after the initial
18273 * position was determined.
18274 * @method onAvailable
18276 onAvailable: function () {
18280 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18283 defaultPadding : {left:0, right:0, top:0, bottom:0},
18286 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18290 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18291 { dragElId: "existingProxyDiv" });
18292 dd.startDrag = function(){
18293 this.constrainTo("parent-id");
18296 * Or you can initalize it using the {@link Roo.Element} object:
18298 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18299 startDrag : function(){
18300 this.constrainTo("parent-id");
18304 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18305 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18306 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18307 * an object containing the sides to pad. For example: {right:10, bottom:10}
18308 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18310 constrainTo : function(constrainTo, pad, inContent){
18311 if(typeof pad == "number"){
18312 pad = {left: pad, right:pad, top:pad, bottom:pad};
18314 pad = pad || this.defaultPadding;
18315 var b = Roo.get(this.getEl()).getBox();
18316 var ce = Roo.get(constrainTo);
18317 var s = ce.getScroll();
18318 var c, cd = ce.dom;
18319 if(cd == document.body){
18320 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18323 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18327 var topSpace = b.y - c.y;
18328 var leftSpace = b.x - c.x;
18330 this.resetConstraints();
18331 this.setXConstraint(leftSpace - (pad.left||0), // left
18332 c.width - leftSpace - b.width - (pad.right||0) //right
18334 this.setYConstraint(topSpace - (pad.top||0), //top
18335 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18340 * Returns a reference to the linked element
18342 * @return {HTMLElement} the html element
18344 getEl: function() {
18345 if (!this._domRef) {
18346 this._domRef = Roo.getDom(this.id);
18349 return this._domRef;
18353 * Returns a reference to the actual element to drag. By default this is
18354 * the same as the html element, but it can be assigned to another
18355 * element. An example of this can be found in Roo.dd.DDProxy
18356 * @method getDragEl
18357 * @return {HTMLElement} the html element
18359 getDragEl: function() {
18360 return Roo.getDom(this.dragElId);
18364 * Sets up the DragDrop object. Must be called in the constructor of any
18365 * Roo.dd.DragDrop subclass
18367 * @param id the id of the linked element
18368 * @param {String} sGroup the group of related items
18369 * @param {object} config configuration attributes
18371 init: function(id, sGroup, config) {
18372 this.initTarget(id, sGroup, config);
18373 if (!Roo.isTouch) {
18374 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18376 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18377 // Event.on(this.id, "selectstart", Event.preventDefault);
18381 * Initializes Targeting functionality only... the object does not
18382 * get a mousedown handler.
18383 * @method initTarget
18384 * @param id the id of the linked element
18385 * @param {String} sGroup the group of related items
18386 * @param {object} config configuration attributes
18388 initTarget: function(id, sGroup, config) {
18390 // configuration attributes
18391 this.config = config || {};
18393 // create a local reference to the drag and drop manager
18394 this.DDM = Roo.dd.DDM;
18395 // initialize the groups array
18398 // assume that we have an element reference instead of an id if the
18399 // parameter is not a string
18400 if (typeof id !== "string") {
18407 // add to an interaction group
18408 this.addToGroup((sGroup) ? sGroup : "default");
18410 // We don't want to register this as the handle with the manager
18411 // so we just set the id rather than calling the setter.
18412 this.handleElId = id;
18414 // the linked element is the element that gets dragged by default
18415 this.setDragElId(id);
18417 // by default, clicked anchors will not start drag operations.
18418 this.invalidHandleTypes = { A: "A" };
18419 this.invalidHandleIds = {};
18420 this.invalidHandleClasses = [];
18422 this.applyConfig();
18424 this.handleOnAvailable();
18428 * Applies the configuration parameters that were passed into the constructor.
18429 * This is supposed to happen at each level through the inheritance chain. So
18430 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18431 * DragDrop in order to get all of the parameters that are available in
18433 * @method applyConfig
18435 applyConfig: function() {
18437 // configurable properties:
18438 // padding, isTarget, maintainOffset, primaryButtonOnly
18439 this.padding = this.config.padding || [0, 0, 0, 0];
18440 this.isTarget = (this.config.isTarget !== false);
18441 this.maintainOffset = (this.config.maintainOffset);
18442 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18447 * Executed when the linked element is available
18448 * @method handleOnAvailable
18451 handleOnAvailable: function() {
18452 this.available = true;
18453 this.resetConstraints();
18454 this.onAvailable();
18458 * Configures the padding for the target zone in px. Effectively expands
18459 * (or reduces) the virtual object size for targeting calculations.
18460 * Supports css-style shorthand; if only one parameter is passed, all sides
18461 * will have that padding, and if only two are passed, the top and bottom
18462 * will have the first param, the left and right the second.
18463 * @method setPadding
18464 * @param {int} iTop Top pad
18465 * @param {int} iRight Right pad
18466 * @param {int} iBot Bot pad
18467 * @param {int} iLeft Left pad
18469 setPadding: function(iTop, iRight, iBot, iLeft) {
18470 // this.padding = [iLeft, iRight, iTop, iBot];
18471 if (!iRight && 0 !== iRight) {
18472 this.padding = [iTop, iTop, iTop, iTop];
18473 } else if (!iBot && 0 !== iBot) {
18474 this.padding = [iTop, iRight, iTop, iRight];
18476 this.padding = [iTop, iRight, iBot, iLeft];
18481 * Stores the initial placement of the linked element.
18482 * @method setInitialPosition
18483 * @param {int} diffX the X offset, default 0
18484 * @param {int} diffY the Y offset, default 0
18486 setInitPosition: function(diffX, diffY) {
18487 var el = this.getEl();
18489 if (!this.DDM.verifyEl(el)) {
18493 var dx = diffX || 0;
18494 var dy = diffY || 0;
18496 var p = Dom.getXY( el );
18498 this.initPageX = p[0] - dx;
18499 this.initPageY = p[1] - dy;
18501 this.lastPageX = p[0];
18502 this.lastPageY = p[1];
18505 this.setStartPosition(p);
18509 * Sets the start position of the element. This is set when the obj
18510 * is initialized, the reset when a drag is started.
18511 * @method setStartPosition
18512 * @param pos current position (from previous lookup)
18515 setStartPosition: function(pos) {
18516 var p = pos || Dom.getXY( this.getEl() );
18517 this.deltaSetXY = null;
18519 this.startPageX = p[0];
18520 this.startPageY = p[1];
18524 * Add this instance to a group of related drag/drop objects. All
18525 * instances belong to at least one group, and can belong to as many
18526 * groups as needed.
18527 * @method addToGroup
18528 * @param sGroup {string} the name of the group
18530 addToGroup: function(sGroup) {
18531 this.groups[sGroup] = true;
18532 this.DDM.regDragDrop(this, sGroup);
18536 * Remove's this instance from the supplied interaction group
18537 * @method removeFromGroup
18538 * @param {string} sGroup The group to drop
18540 removeFromGroup: function(sGroup) {
18541 if (this.groups[sGroup]) {
18542 delete this.groups[sGroup];
18545 this.DDM.removeDDFromGroup(this, sGroup);
18549 * Allows you to specify that an element other than the linked element
18550 * will be moved with the cursor during a drag
18551 * @method setDragElId
18552 * @param id {string} the id of the element that will be used to initiate the drag
18554 setDragElId: function(id) {
18555 this.dragElId = id;
18559 * Allows you to specify a child of the linked element that should be
18560 * used to initiate the drag operation. An example of this would be if
18561 * you have a content div with text and links. Clicking anywhere in the
18562 * content area would normally start the drag operation. Use this method
18563 * to specify that an element inside of the content div is the element
18564 * that starts the drag operation.
18565 * @method setHandleElId
18566 * @param id {string} the id of the element that will be used to
18567 * initiate the drag.
18569 setHandleElId: function(id) {
18570 if (typeof id !== "string") {
18573 this.handleElId = id;
18574 this.DDM.regHandle(this.id, id);
18578 * Allows you to set an element outside of the linked element as a drag
18580 * @method setOuterHandleElId
18581 * @param id the id of the element that will be used to initiate the drag
18583 setOuterHandleElId: function(id) {
18584 if (typeof id !== "string") {
18587 Event.on(id, "mousedown",
18588 this.handleMouseDown, this);
18589 this.setHandleElId(id);
18591 this.hasOuterHandles = true;
18595 * Remove all drag and drop hooks for this element
18598 unreg: function() {
18599 Event.un(this.id, "mousedown",
18600 this.handleMouseDown);
18601 Event.un(this.id, "touchstart",
18602 this.handleMouseDown);
18603 this._domRef = null;
18604 this.DDM._remove(this);
18607 destroy : function(){
18612 * Returns true if this instance is locked, or the drag drop mgr is locked
18613 * (meaning that all drag/drop is disabled on the page.)
18615 * @return {boolean} true if this obj or all drag/drop is locked, else
18618 isLocked: function() {
18619 return (this.DDM.isLocked() || this.locked);
18623 * Fired when this object is clicked
18624 * @method handleMouseDown
18626 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18629 handleMouseDown: function(e, oDD){
18631 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18632 //Roo.log('not touch/ button !=0');
18635 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18636 return; // double touch..
18640 if (this.isLocked()) {
18641 //Roo.log('locked');
18645 this.DDM.refreshCache(this.groups);
18646 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18647 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18648 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18649 //Roo.log('no outer handes or not over target');
18652 // Roo.log('check validator');
18653 if (this.clickValidator(e)) {
18654 // Roo.log('validate success');
18655 // set the initial element position
18656 this.setStartPosition();
18659 this.b4MouseDown(e);
18660 this.onMouseDown(e);
18662 this.DDM.handleMouseDown(e, this);
18664 this.DDM.stopEvent(e);
18672 clickValidator: function(e) {
18673 var target = e.getTarget();
18674 return ( this.isValidHandleChild(target) &&
18675 (this.id == this.handleElId ||
18676 this.DDM.handleWasClicked(target, this.id)) );
18680 * Allows you to specify a tag name that should not start a drag operation
18681 * when clicked. This is designed to facilitate embedding links within a
18682 * drag handle that do something other than start the drag.
18683 * @method addInvalidHandleType
18684 * @param {string} tagName the type of element to exclude
18686 addInvalidHandleType: function(tagName) {
18687 var type = tagName.toUpperCase();
18688 this.invalidHandleTypes[type] = type;
18692 * Lets you to specify an element id for a child of a drag handle
18693 * that should not initiate a drag
18694 * @method addInvalidHandleId
18695 * @param {string} id the element id of the element you wish to ignore
18697 addInvalidHandleId: function(id) {
18698 if (typeof id !== "string") {
18701 this.invalidHandleIds[id] = id;
18705 * Lets you specify a css class of elements that will not initiate a drag
18706 * @method addInvalidHandleClass
18707 * @param {string} cssClass the class of the elements you wish to ignore
18709 addInvalidHandleClass: function(cssClass) {
18710 this.invalidHandleClasses.push(cssClass);
18714 * Unsets an excluded tag name set by addInvalidHandleType
18715 * @method removeInvalidHandleType
18716 * @param {string} tagName the type of element to unexclude
18718 removeInvalidHandleType: function(tagName) {
18719 var type = tagName.toUpperCase();
18720 // this.invalidHandleTypes[type] = null;
18721 delete this.invalidHandleTypes[type];
18725 * Unsets an invalid handle id
18726 * @method removeInvalidHandleId
18727 * @param {string} id the id of the element to re-enable
18729 removeInvalidHandleId: function(id) {
18730 if (typeof id !== "string") {
18733 delete this.invalidHandleIds[id];
18737 * Unsets an invalid css class
18738 * @method removeInvalidHandleClass
18739 * @param {string} cssClass the class of the element(s) you wish to
18742 removeInvalidHandleClass: function(cssClass) {
18743 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18744 if (this.invalidHandleClasses[i] == cssClass) {
18745 delete this.invalidHandleClasses[i];
18751 * Checks the tag exclusion list to see if this click should be ignored
18752 * @method isValidHandleChild
18753 * @param {HTMLElement} node the HTMLElement to evaluate
18754 * @return {boolean} true if this is a valid tag type, false if not
18756 isValidHandleChild: function(node) {
18759 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18762 nodeName = node.nodeName.toUpperCase();
18764 nodeName = node.nodeName;
18766 valid = valid && !this.invalidHandleTypes[nodeName];
18767 valid = valid && !this.invalidHandleIds[node.id];
18769 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18770 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18779 * Create the array of horizontal tick marks if an interval was specified
18780 * in setXConstraint().
18781 * @method setXTicks
18784 setXTicks: function(iStartX, iTickSize) {
18786 this.xTickSize = iTickSize;
18790 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18792 this.xTicks[this.xTicks.length] = i;
18797 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18799 this.xTicks[this.xTicks.length] = i;
18804 this.xTicks.sort(this.DDM.numericSort) ;
18808 * Create the array of vertical tick marks if an interval was specified in
18809 * setYConstraint().
18810 * @method setYTicks
18813 setYTicks: function(iStartY, iTickSize) {
18815 this.yTickSize = iTickSize;
18819 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18821 this.yTicks[this.yTicks.length] = i;
18826 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18828 this.yTicks[this.yTicks.length] = i;
18833 this.yTicks.sort(this.DDM.numericSort) ;
18837 * By default, the element can be dragged any place on the screen. Use
18838 * this method to limit the horizontal travel of the element. Pass in
18839 * 0,0 for the parameters if you want to lock the drag to the y axis.
18840 * @method setXConstraint
18841 * @param {int} iLeft the number of pixels the element can move to the left
18842 * @param {int} iRight the number of pixels the element can move to the
18844 * @param {int} iTickSize optional parameter for specifying that the
18846 * should move iTickSize pixels at a time.
18848 setXConstraint: function(iLeft, iRight, iTickSize) {
18849 this.leftConstraint = iLeft;
18850 this.rightConstraint = iRight;
18852 this.minX = this.initPageX - iLeft;
18853 this.maxX = this.initPageX + iRight;
18854 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18856 this.constrainX = true;
18860 * Clears any constraints applied to this instance. Also clears ticks
18861 * since they can't exist independent of a constraint at this time.
18862 * @method clearConstraints
18864 clearConstraints: function() {
18865 this.constrainX = false;
18866 this.constrainY = false;
18871 * Clears any tick interval defined for this instance
18872 * @method clearTicks
18874 clearTicks: function() {
18875 this.xTicks = null;
18876 this.yTicks = null;
18877 this.xTickSize = 0;
18878 this.yTickSize = 0;
18882 * By default, the element can be dragged any place on the screen. Set
18883 * this to limit the vertical travel of the element. Pass in 0,0 for the
18884 * parameters if you want to lock the drag to the x axis.
18885 * @method setYConstraint
18886 * @param {int} iUp the number of pixels the element can move up
18887 * @param {int} iDown the number of pixels the element can move down
18888 * @param {int} iTickSize optional parameter for specifying that the
18889 * element should move iTickSize pixels at a time.
18891 setYConstraint: function(iUp, iDown, iTickSize) {
18892 this.topConstraint = iUp;
18893 this.bottomConstraint = iDown;
18895 this.minY = this.initPageY - iUp;
18896 this.maxY = this.initPageY + iDown;
18897 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
18899 this.constrainY = true;
18904 * resetConstraints must be called if you manually reposition a dd element.
18905 * @method resetConstraints
18906 * @param {boolean} maintainOffset
18908 resetConstraints: function() {
18911 // Maintain offsets if necessary
18912 if (this.initPageX || this.initPageX === 0) {
18913 // figure out how much this thing has moved
18914 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
18915 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
18917 this.setInitPosition(dx, dy);
18919 // This is the first time we have detected the element's position
18921 this.setInitPosition();
18924 if (this.constrainX) {
18925 this.setXConstraint( this.leftConstraint,
18926 this.rightConstraint,
18930 if (this.constrainY) {
18931 this.setYConstraint( this.topConstraint,
18932 this.bottomConstraint,
18938 * Normally the drag element is moved pixel by pixel, but we can specify
18939 * that it move a number of pixels at a time. This method resolves the
18940 * location when we have it set up like this.
18942 * @param {int} val where we want to place the object
18943 * @param {int[]} tickArray sorted array of valid points
18944 * @return {int} the closest tick
18947 getTick: function(val, tickArray) {
18950 // If tick interval is not defined, it is effectively 1 pixel,
18951 // so we return the value passed to us.
18953 } else if (tickArray[0] >= val) {
18954 // The value is lower than the first tick, so we return the first
18956 return tickArray[0];
18958 for (var i=0, len=tickArray.length; i<len; ++i) {
18960 if (tickArray[next] && tickArray[next] >= val) {
18961 var diff1 = val - tickArray[i];
18962 var diff2 = tickArray[next] - val;
18963 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
18967 // The value is larger than the last tick, so we return the last
18969 return tickArray[tickArray.length - 1];
18976 * @return {string} string representation of the dd obj
18978 toString: function() {
18979 return ("DragDrop " + this.id);
18987 * Ext JS Library 1.1.1
18988 * Copyright(c) 2006-2007, Ext JS, LLC.
18990 * Originally Released Under LGPL - original licence link has changed is not relivant.
18993 * <script type="text/javascript">
18998 * The drag and drop utility provides a framework for building drag and drop
18999 * applications. In addition to enabling drag and drop for specific elements,
19000 * the drag and drop elements are tracked by the manager class, and the
19001 * interactions between the various elements are tracked during the drag and
19002 * the implementing code is notified about these important moments.
19005 // Only load the library once. Rewriting the manager class would orphan
19006 // existing drag and drop instances.
19007 if (!Roo.dd.DragDropMgr) {
19010 * @class Roo.dd.DragDropMgr
19011 * DragDropMgr is a singleton that tracks the element interaction for
19012 * all DragDrop items in the window. Generally, you will not call
19013 * this class directly, but it does have helper methods that could
19014 * be useful in your DragDrop implementations.
19017 Roo.dd.DragDropMgr = function() {
19019 var Event = Roo.EventManager;
19024 * Two dimensional Array of registered DragDrop objects. The first
19025 * dimension is the DragDrop item group, the second the DragDrop
19028 * @type {string: string}
19035 * Array of element ids defined as drag handles. Used to determine
19036 * if the element that generated the mousedown event is actually the
19037 * handle and not the html element itself.
19038 * @property handleIds
19039 * @type {string: string}
19046 * the DragDrop object that is currently being dragged
19047 * @property dragCurrent
19055 * the DragDrop object(s) that are being hovered over
19056 * @property dragOvers
19064 * the X distance between the cursor and the object being dragged
19073 * the Y distance between the cursor and the object being dragged
19082 * Flag to determine if we should prevent the default behavior of the
19083 * events we define. By default this is true, but this can be set to
19084 * false if you need the default behavior (not recommended)
19085 * @property preventDefault
19089 preventDefault: true,
19092 * Flag to determine if we should stop the propagation of the events
19093 * we generate. This is true by default but you may want to set it to
19094 * false if the html element contains other features that require the
19096 * @property stopPropagation
19100 stopPropagation: true,
19103 * Internal flag that is set to true when drag and drop has been
19105 * @property initialized
19112 * All drag and drop can be disabled.
19120 * Called the first time an element is registered.
19126 this.initialized = true;
19130 * In point mode, drag and drop interaction is defined by the
19131 * location of the cursor during the drag/drop
19139 * In intersect mode, drag and drop interactio nis defined by the
19140 * overlap of two or more drag and drop objects.
19141 * @property INTERSECT
19148 * The current drag and drop mode. Default: POINT
19156 * Runs method on all drag and drop objects
19157 * @method _execOnAll
19161 _execOnAll: function(sMethod, args) {
19162 for (var i in this.ids) {
19163 for (var j in this.ids[i]) {
19164 var oDD = this.ids[i][j];
19165 if (! this.isTypeOfDD(oDD)) {
19168 oDD[sMethod].apply(oDD, args);
19174 * Drag and drop initialization. Sets up the global event handlers
19179 _onLoad: function() {
19183 if (!Roo.isTouch) {
19184 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19185 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19187 Event.on(document, "touchend", this.handleMouseUp, this, true);
19188 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19190 Event.on(window, "unload", this._onUnload, this, true);
19191 Event.on(window, "resize", this._onResize, this, true);
19192 // Event.on(window, "mouseout", this._test);
19197 * Reset constraints on all drag and drop objs
19198 * @method _onResize
19202 _onResize: function(e) {
19203 this._execOnAll("resetConstraints", []);
19207 * Lock all drag and drop functionality
19211 lock: function() { this.locked = true; },
19214 * Unlock all drag and drop functionality
19218 unlock: function() { this.locked = false; },
19221 * Is drag and drop locked?
19223 * @return {boolean} True if drag and drop is locked, false otherwise.
19226 isLocked: function() { return this.locked; },
19229 * Location cache that is set for all drag drop objects when a drag is
19230 * initiated, cleared when the drag is finished.
19231 * @property locationCache
19238 * Set useCache to false if you want to force object the lookup of each
19239 * drag and drop linked element constantly during a drag.
19240 * @property useCache
19247 * The number of pixels that the mouse needs to move after the
19248 * mousedown before the drag is initiated. Default=3;
19249 * @property clickPixelThresh
19253 clickPixelThresh: 3,
19256 * The number of milliseconds after the mousedown event to initiate the
19257 * drag if we don't get a mouseup event. Default=1000
19258 * @property clickTimeThresh
19262 clickTimeThresh: 350,
19265 * Flag that indicates that either the drag pixel threshold or the
19266 * mousdown time threshold has been met
19267 * @property dragThreshMet
19272 dragThreshMet: false,
19275 * Timeout used for the click time threshold
19276 * @property clickTimeout
19281 clickTimeout: null,
19284 * The X position of the mousedown event stored for later use when a
19285 * drag threshold is met.
19294 * The Y position of the mousedown event stored for later use when a
19295 * drag threshold is met.
19304 * Each DragDrop instance must be registered with the DragDropMgr.
19305 * This is executed in DragDrop.init()
19306 * @method regDragDrop
19307 * @param {DragDrop} oDD the DragDrop object to register
19308 * @param {String} sGroup the name of the group this element belongs to
19311 regDragDrop: function(oDD, sGroup) {
19312 if (!this.initialized) { this.init(); }
19314 if (!this.ids[sGroup]) {
19315 this.ids[sGroup] = {};
19317 this.ids[sGroup][oDD.id] = oDD;
19321 * Removes the supplied dd instance from the supplied group. Executed
19322 * by DragDrop.removeFromGroup, so don't call this function directly.
19323 * @method removeDDFromGroup
19327 removeDDFromGroup: function(oDD, sGroup) {
19328 if (!this.ids[sGroup]) {
19329 this.ids[sGroup] = {};
19332 var obj = this.ids[sGroup];
19333 if (obj && obj[oDD.id]) {
19334 delete obj[oDD.id];
19339 * Unregisters a drag and drop item. This is executed in
19340 * DragDrop.unreg, use that method instead of calling this directly.
19345 _remove: function(oDD) {
19346 for (var g in oDD.groups) {
19347 if (g && this.ids[g][oDD.id]) {
19348 delete this.ids[g][oDD.id];
19351 delete this.handleIds[oDD.id];
19355 * Each DragDrop handle element must be registered. This is done
19356 * automatically when executing DragDrop.setHandleElId()
19357 * @method regHandle
19358 * @param {String} sDDId the DragDrop id this element is a handle for
19359 * @param {String} sHandleId the id of the element that is the drag
19363 regHandle: function(sDDId, sHandleId) {
19364 if (!this.handleIds[sDDId]) {
19365 this.handleIds[sDDId] = {};
19367 this.handleIds[sDDId][sHandleId] = sHandleId;
19371 * Utility function to determine if a given element has been
19372 * registered as a drag drop item.
19373 * @method isDragDrop
19374 * @param {String} id the element id to check
19375 * @return {boolean} true if this element is a DragDrop item,
19379 isDragDrop: function(id) {
19380 return ( this.getDDById(id) ) ? true : false;
19384 * Returns the drag and drop instances that are in all groups the
19385 * passed in instance belongs to.
19386 * @method getRelated
19387 * @param {DragDrop} p_oDD the obj to get related data for
19388 * @param {boolean} bTargetsOnly if true, only return targetable objs
19389 * @return {DragDrop[]} the related instances
19392 getRelated: function(p_oDD, bTargetsOnly) {
19394 for (var i in p_oDD.groups) {
19395 for (j in this.ids[i]) {
19396 var dd = this.ids[i][j];
19397 if (! this.isTypeOfDD(dd)) {
19400 if (!bTargetsOnly || dd.isTarget) {
19401 oDDs[oDDs.length] = dd;
19410 * Returns true if the specified dd target is a legal target for
19411 * the specifice drag obj
19412 * @method isLegalTarget
19413 * @param {DragDrop} the drag obj
19414 * @param {DragDrop} the target
19415 * @return {boolean} true if the target is a legal target for the
19419 isLegalTarget: function (oDD, oTargetDD) {
19420 var targets = this.getRelated(oDD, true);
19421 for (var i=0, len=targets.length;i<len;++i) {
19422 if (targets[i].id == oTargetDD.id) {
19431 * My goal is to be able to transparently determine if an object is
19432 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19433 * returns "object", oDD.constructor.toString() always returns
19434 * "DragDrop" and not the name of the subclass. So for now it just
19435 * evaluates a well-known variable in DragDrop.
19436 * @method isTypeOfDD
19437 * @param {Object} the object to evaluate
19438 * @return {boolean} true if typeof oDD = DragDrop
19441 isTypeOfDD: function (oDD) {
19442 return (oDD && oDD.__ygDragDrop);
19446 * Utility function to determine if a given element has been
19447 * registered as a drag drop handle for the given Drag Drop object.
19449 * @param {String} id the element id to check
19450 * @return {boolean} true if this element is a DragDrop handle, false
19454 isHandle: function(sDDId, sHandleId) {
19455 return ( this.handleIds[sDDId] &&
19456 this.handleIds[sDDId][sHandleId] );
19460 * Returns the DragDrop instance for a given id
19461 * @method getDDById
19462 * @param {String} id the id of the DragDrop object
19463 * @return {DragDrop} the drag drop object, null if it is not found
19466 getDDById: function(id) {
19467 for (var i in this.ids) {
19468 if (this.ids[i][id]) {
19469 return this.ids[i][id];
19476 * Fired after a registered DragDrop object gets the mousedown event.
19477 * Sets up the events required to track the object being dragged
19478 * @method handleMouseDown
19479 * @param {Event} e the event
19480 * @param oDD the DragDrop object being dragged
19484 handleMouseDown: function(e, oDD) {
19486 Roo.QuickTips.disable();
19488 this.currentTarget = e.getTarget();
19490 this.dragCurrent = oDD;
19492 var el = oDD.getEl();
19494 // track start position
19495 this.startX = e.getPageX();
19496 this.startY = e.getPageY();
19498 this.deltaX = this.startX - el.offsetLeft;
19499 this.deltaY = this.startY - el.offsetTop;
19501 this.dragThreshMet = false;
19503 this.clickTimeout = setTimeout(
19505 var DDM = Roo.dd.DDM;
19506 DDM.startDrag(DDM.startX, DDM.startY);
19508 this.clickTimeThresh );
19512 * Fired when either the drag pixel threshol or the mousedown hold
19513 * time threshold has been met.
19514 * @method startDrag
19515 * @param x {int} the X position of the original mousedown
19516 * @param y {int} the Y position of the original mousedown
19519 startDrag: function(x, y) {
19520 clearTimeout(this.clickTimeout);
19521 if (this.dragCurrent) {
19522 this.dragCurrent.b4StartDrag(x, y);
19523 this.dragCurrent.startDrag(x, y);
19525 this.dragThreshMet = true;
19529 * Internal function to handle the mouseup event. Will be invoked
19530 * from the context of the document.
19531 * @method handleMouseUp
19532 * @param {Event} e the event
19536 handleMouseUp: function(e) {
19539 Roo.QuickTips.enable();
19541 if (! this.dragCurrent) {
19545 clearTimeout(this.clickTimeout);
19547 if (this.dragThreshMet) {
19548 this.fireEvents(e, true);
19558 * Utility to stop event propagation and event default, if these
19559 * features are turned on.
19560 * @method stopEvent
19561 * @param {Event} e the event as returned by this.getEvent()
19564 stopEvent: function(e){
19565 if(this.stopPropagation) {
19566 e.stopPropagation();
19569 if (this.preventDefault) {
19570 e.preventDefault();
19575 * Internal function to clean up event handlers after the drag
19576 * operation is complete
19578 * @param {Event} e the event
19582 stopDrag: function(e) {
19583 // Fire the drag end event for the item that was dragged
19584 if (this.dragCurrent) {
19585 if (this.dragThreshMet) {
19586 this.dragCurrent.b4EndDrag(e);
19587 this.dragCurrent.endDrag(e);
19590 this.dragCurrent.onMouseUp(e);
19593 this.dragCurrent = null;
19594 this.dragOvers = {};
19598 * Internal function to handle the mousemove event. Will be invoked
19599 * from the context of the html element.
19601 * @TODO figure out what we can do about mouse events lost when the
19602 * user drags objects beyond the window boundary. Currently we can
19603 * detect this in internet explorer by verifying that the mouse is
19604 * down during the mousemove event. Firefox doesn't give us the
19605 * button state on the mousemove event.
19606 * @method handleMouseMove
19607 * @param {Event} e the event
19611 handleMouseMove: function(e) {
19612 if (! this.dragCurrent) {
19616 // var button = e.which || e.button;
19618 // check for IE mouseup outside of page boundary
19619 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19621 return this.handleMouseUp(e);
19624 if (!this.dragThreshMet) {
19625 var diffX = Math.abs(this.startX - e.getPageX());
19626 var diffY = Math.abs(this.startY - e.getPageY());
19627 if (diffX > this.clickPixelThresh ||
19628 diffY > this.clickPixelThresh) {
19629 this.startDrag(this.startX, this.startY);
19633 if (this.dragThreshMet) {
19634 this.dragCurrent.b4Drag(e);
19635 this.dragCurrent.onDrag(e);
19636 if(!this.dragCurrent.moveOnly){
19637 this.fireEvents(e, false);
19647 * Iterates over all of the DragDrop elements to find ones we are
19648 * hovering over or dropping on
19649 * @method fireEvents
19650 * @param {Event} e the event
19651 * @param {boolean} isDrop is this a drop op or a mouseover op?
19655 fireEvents: function(e, isDrop) {
19656 var dc = this.dragCurrent;
19658 // If the user did the mouse up outside of the window, we could
19659 // get here even though we have ended the drag.
19660 if (!dc || dc.isLocked()) {
19664 var pt = e.getPoint();
19666 // cache the previous dragOver array
19672 var enterEvts = [];
19674 // Check to see if the object(s) we were hovering over is no longer
19675 // being hovered over so we can fire the onDragOut event
19676 for (var i in this.dragOvers) {
19678 var ddo = this.dragOvers[i];
19680 if (! this.isTypeOfDD(ddo)) {
19684 if (! this.isOverTarget(pt, ddo, this.mode)) {
19685 outEvts.push( ddo );
19688 oldOvers[i] = true;
19689 delete this.dragOvers[i];
19692 for (var sGroup in dc.groups) {
19694 if ("string" != typeof sGroup) {
19698 for (i in this.ids[sGroup]) {
19699 var oDD = this.ids[sGroup][i];
19700 if (! this.isTypeOfDD(oDD)) {
19704 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19705 if (this.isOverTarget(pt, oDD, this.mode)) {
19706 // look for drop interactions
19708 dropEvts.push( oDD );
19709 // look for drag enter and drag over interactions
19712 // initial drag over: dragEnter fires
19713 if (!oldOvers[oDD.id]) {
19714 enterEvts.push( oDD );
19715 // subsequent drag overs: dragOver fires
19717 overEvts.push( oDD );
19720 this.dragOvers[oDD.id] = oDD;
19728 if (outEvts.length) {
19729 dc.b4DragOut(e, outEvts);
19730 dc.onDragOut(e, outEvts);
19733 if (enterEvts.length) {
19734 dc.onDragEnter(e, enterEvts);
19737 if (overEvts.length) {
19738 dc.b4DragOver(e, overEvts);
19739 dc.onDragOver(e, overEvts);
19742 if (dropEvts.length) {
19743 dc.b4DragDrop(e, dropEvts);
19744 dc.onDragDrop(e, dropEvts);
19748 // fire dragout events
19750 for (i=0, len=outEvts.length; i<len; ++i) {
19751 dc.b4DragOut(e, outEvts[i].id);
19752 dc.onDragOut(e, outEvts[i].id);
19755 // fire enter events
19756 for (i=0,len=enterEvts.length; i<len; ++i) {
19757 // dc.b4DragEnter(e, oDD.id);
19758 dc.onDragEnter(e, enterEvts[i].id);
19761 // fire over events
19762 for (i=0,len=overEvts.length; i<len; ++i) {
19763 dc.b4DragOver(e, overEvts[i].id);
19764 dc.onDragOver(e, overEvts[i].id);
19767 // fire drop events
19768 for (i=0, len=dropEvts.length; i<len; ++i) {
19769 dc.b4DragDrop(e, dropEvts[i].id);
19770 dc.onDragDrop(e, dropEvts[i].id);
19775 // notify about a drop that did not find a target
19776 if (isDrop && !dropEvts.length) {
19777 dc.onInvalidDrop(e);
19783 * Helper function for getting the best match from the list of drag
19784 * and drop objects returned by the drag and drop events when we are
19785 * in INTERSECT mode. It returns either the first object that the
19786 * cursor is over, or the object that has the greatest overlap with
19787 * the dragged element.
19788 * @method getBestMatch
19789 * @param {DragDrop[]} dds The array of drag and drop objects
19791 * @return {DragDrop} The best single match
19794 getBestMatch: function(dds) {
19796 // Return null if the input is not what we expect
19797 //if (!dds || !dds.length || dds.length == 0) {
19799 // If there is only one item, it wins
19800 //} else if (dds.length == 1) {
19802 var len = dds.length;
19807 // Loop through the targeted items
19808 for (var i=0; i<len; ++i) {
19810 // If the cursor is over the object, it wins. If the
19811 // cursor is over multiple matches, the first one we come
19813 if (dd.cursorIsOver) {
19816 // Otherwise the object with the most overlap wins
19819 winner.overlap.getArea() < dd.overlap.getArea()) {
19830 * Refreshes the cache of the top-left and bottom-right points of the
19831 * drag and drop objects in the specified group(s). This is in the
19832 * format that is stored in the drag and drop instance, so typical
19835 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19839 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19841 * @TODO this really should be an indexed array. Alternatively this
19842 * method could accept both.
19843 * @method refreshCache
19844 * @param {Object} groups an associative array of groups to refresh
19847 refreshCache: function(groups) {
19848 for (var sGroup in groups) {
19849 if ("string" != typeof sGroup) {
19852 for (var i in this.ids[sGroup]) {
19853 var oDD = this.ids[sGroup][i];
19855 if (this.isTypeOfDD(oDD)) {
19856 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19857 var loc = this.getLocation(oDD);
19859 this.locationCache[oDD.id] = loc;
19861 delete this.locationCache[oDD.id];
19862 // this will unregister the drag and drop object if
19863 // the element is not in a usable state
19872 * This checks to make sure an element exists and is in the DOM. The
19873 * main purpose is to handle cases where innerHTML is used to remove
19874 * drag and drop objects from the DOM. IE provides an 'unspecified
19875 * error' when trying to access the offsetParent of such an element
19877 * @param {HTMLElement} el the element to check
19878 * @return {boolean} true if the element looks usable
19881 verifyEl: function(el) {
19886 parent = el.offsetParent;
19889 parent = el.offsetParent;
19900 * Returns a Region object containing the drag and drop element's position
19901 * and size, including the padding configured for it
19902 * @method getLocation
19903 * @param {DragDrop} oDD the drag and drop object to get the
19905 * @return {Roo.lib.Region} a Region object representing the total area
19906 * the element occupies, including any padding
19907 * the instance is configured for.
19910 getLocation: function(oDD) {
19911 if (! this.isTypeOfDD(oDD)) {
19915 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
19918 pos= Roo.lib.Dom.getXY(el);
19926 x2 = x1 + el.offsetWidth;
19928 y2 = y1 + el.offsetHeight;
19930 t = y1 - oDD.padding[0];
19931 r = x2 + oDD.padding[1];
19932 b = y2 + oDD.padding[2];
19933 l = x1 - oDD.padding[3];
19935 return new Roo.lib.Region( t, r, b, l );
19939 * Checks the cursor location to see if it over the target
19940 * @method isOverTarget
19941 * @param {Roo.lib.Point} pt The point to evaluate
19942 * @param {DragDrop} oTarget the DragDrop object we are inspecting
19943 * @return {boolean} true if the mouse is over the target
19947 isOverTarget: function(pt, oTarget, intersect) {
19948 // use cache if available
19949 var loc = this.locationCache[oTarget.id];
19950 if (!loc || !this.useCache) {
19951 loc = this.getLocation(oTarget);
19952 this.locationCache[oTarget.id] = loc;
19960 oTarget.cursorIsOver = loc.contains( pt );
19962 // DragDrop is using this as a sanity check for the initial mousedown
19963 // in this case we are done. In POINT mode, if the drag obj has no
19964 // contraints, we are also done. Otherwise we need to evaluate the
19965 // location of the target as related to the actual location of the
19966 // dragged element.
19967 var dc = this.dragCurrent;
19968 if (!dc || !dc.getTargetCoord ||
19969 (!intersect && !dc.constrainX && !dc.constrainY)) {
19970 return oTarget.cursorIsOver;
19973 oTarget.overlap = null;
19975 // Get the current location of the drag element, this is the
19976 // location of the mouse event less the delta that represents
19977 // where the original mousedown happened on the element. We
19978 // need to consider constraints and ticks as well.
19979 var pos = dc.getTargetCoord(pt.x, pt.y);
19981 var el = dc.getDragEl();
19982 var curRegion = new Roo.lib.Region( pos.y,
19983 pos.x + el.offsetWidth,
19984 pos.y + el.offsetHeight,
19987 var overlap = curRegion.intersect(loc);
19990 oTarget.overlap = overlap;
19991 return (intersect) ? true : oTarget.cursorIsOver;
19998 * unload event handler
19999 * @method _onUnload
20003 _onUnload: function(e, me) {
20004 Roo.dd.DragDropMgr.unregAll();
20008 * Cleans up the drag and drop events and objects.
20013 unregAll: function() {
20015 if (this.dragCurrent) {
20017 this.dragCurrent = null;
20020 this._execOnAll("unreg", []);
20022 for (i in this.elementCache) {
20023 delete this.elementCache[i];
20026 this.elementCache = {};
20031 * A cache of DOM elements
20032 * @property elementCache
20039 * Get the wrapper for the DOM element specified
20040 * @method getElWrapper
20041 * @param {String} id the id of the element to get
20042 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20044 * @deprecated This wrapper isn't that useful
20047 getElWrapper: function(id) {
20048 var oWrapper = this.elementCache[id];
20049 if (!oWrapper || !oWrapper.el) {
20050 oWrapper = this.elementCache[id] =
20051 new this.ElementWrapper(Roo.getDom(id));
20057 * Returns the actual DOM element
20058 * @method getElement
20059 * @param {String} id the id of the elment to get
20060 * @return {Object} The element
20061 * @deprecated use Roo.getDom instead
20064 getElement: function(id) {
20065 return Roo.getDom(id);
20069 * Returns the style property for the DOM element (i.e.,
20070 * document.getElById(id).style)
20072 * @param {String} id the id of the elment to get
20073 * @return {Object} The style property of the element
20074 * @deprecated use Roo.getDom instead
20077 getCss: function(id) {
20078 var el = Roo.getDom(id);
20079 return (el) ? el.style : null;
20083 * Inner class for cached elements
20084 * @class DragDropMgr.ElementWrapper
20089 ElementWrapper: function(el) {
20094 this.el = el || null;
20099 this.id = this.el && el.id;
20101 * A reference to the style property
20104 this.css = this.el && el.style;
20108 * Returns the X position of an html element
20110 * @param el the element for which to get the position
20111 * @return {int} the X coordinate
20113 * @deprecated use Roo.lib.Dom.getX instead
20116 getPosX: function(el) {
20117 return Roo.lib.Dom.getX(el);
20121 * Returns the Y position of an html element
20123 * @param el the element for which to get the position
20124 * @return {int} the Y coordinate
20125 * @deprecated use Roo.lib.Dom.getY instead
20128 getPosY: function(el) {
20129 return Roo.lib.Dom.getY(el);
20133 * Swap two nodes. In IE, we use the native method, for others we
20134 * emulate the IE behavior
20136 * @param n1 the first node to swap
20137 * @param n2 the other node to swap
20140 swapNode: function(n1, n2) {
20144 var p = n2.parentNode;
20145 var s = n2.nextSibling;
20148 p.insertBefore(n1, n2);
20149 } else if (n2 == n1.nextSibling) {
20150 p.insertBefore(n2, n1);
20152 n1.parentNode.replaceChild(n2, n1);
20153 p.insertBefore(n1, s);
20159 * Returns the current scroll position
20160 * @method getScroll
20164 getScroll: function () {
20165 var t, l, dde=document.documentElement, db=document.body;
20166 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20168 l = dde.scrollLeft;
20175 return { top: t, left: l };
20179 * Returns the specified element style property
20181 * @param {HTMLElement} el the element
20182 * @param {string} styleProp the style property
20183 * @return {string} The value of the style property
20184 * @deprecated use Roo.lib.Dom.getStyle
20187 getStyle: function(el, styleProp) {
20188 return Roo.fly(el).getStyle(styleProp);
20192 * Gets the scrollTop
20193 * @method getScrollTop
20194 * @return {int} the document's scrollTop
20197 getScrollTop: function () { return this.getScroll().top; },
20200 * Gets the scrollLeft
20201 * @method getScrollLeft
20202 * @return {int} the document's scrollTop
20205 getScrollLeft: function () { return this.getScroll().left; },
20208 * Sets the x/y position of an element to the location of the
20211 * @param {HTMLElement} moveEl The element to move
20212 * @param {HTMLElement} targetEl The position reference element
20215 moveToEl: function (moveEl, targetEl) {
20216 var aCoord = Roo.lib.Dom.getXY(targetEl);
20217 Roo.lib.Dom.setXY(moveEl, aCoord);
20221 * Numeric array sort function
20222 * @method numericSort
20225 numericSort: function(a, b) { return (a - b); },
20229 * @property _timeoutCount
20236 * Trying to make the load order less important. Without this we get
20237 * an error if this file is loaded before the Event Utility.
20238 * @method _addListeners
20242 _addListeners: function() {
20243 var DDM = Roo.dd.DDM;
20244 if ( Roo.lib.Event && document ) {
20247 if (DDM._timeoutCount > 2000) {
20249 setTimeout(DDM._addListeners, 10);
20250 if (document && document.body) {
20251 DDM._timeoutCount += 1;
20258 * Recursively searches the immediate parent and all child nodes for
20259 * the handle element in order to determine wheter or not it was
20261 * @method handleWasClicked
20262 * @param node the html element to inspect
20265 handleWasClicked: function(node, id) {
20266 if (this.isHandle(id, node.id)) {
20269 // check to see if this is a text node child of the one we want
20270 var p = node.parentNode;
20273 if (this.isHandle(id, p.id)) {
20288 // shorter alias, save a few bytes
20289 Roo.dd.DDM = Roo.dd.DragDropMgr;
20290 Roo.dd.DDM._addListeners();
20294 * Ext JS Library 1.1.1
20295 * Copyright(c) 2006-2007, Ext JS, LLC.
20297 * Originally Released Under LGPL - original licence link has changed is not relivant.
20300 * <script type="text/javascript">
20305 * A DragDrop implementation where the linked element follows the
20306 * mouse cursor during a drag.
20307 * @extends Roo.dd.DragDrop
20309 * @param {String} id the id of the linked element
20310 * @param {String} sGroup the group of related DragDrop items
20311 * @param {object} config an object containing configurable attributes
20312 * Valid properties for DD:
20315 Roo.dd.DD = function(id, sGroup, config) {
20317 this.init(id, sGroup, config);
20321 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20324 * When set to true, the utility automatically tries to scroll the browser
20325 * window wehn a drag and drop element is dragged near the viewport boundary.
20326 * Defaults to true.
20333 * Sets the pointer offset to the distance between the linked element's top
20334 * left corner and the location the element was clicked
20335 * @method autoOffset
20336 * @param {int} iPageX the X coordinate of the click
20337 * @param {int} iPageY the Y coordinate of the click
20339 autoOffset: function(iPageX, iPageY) {
20340 var x = iPageX - this.startPageX;
20341 var y = iPageY - this.startPageY;
20342 this.setDelta(x, y);
20346 * Sets the pointer offset. You can call this directly to force the
20347 * offset to be in a particular location (e.g., pass in 0,0 to set it
20348 * to the center of the object)
20350 * @param {int} iDeltaX the distance from the left
20351 * @param {int} iDeltaY the distance from the top
20353 setDelta: function(iDeltaX, iDeltaY) {
20354 this.deltaX = iDeltaX;
20355 this.deltaY = iDeltaY;
20359 * Sets the drag element to the location of the mousedown or click event,
20360 * maintaining the cursor location relative to the location on the element
20361 * that was clicked. Override this if you want to place the element in a
20362 * location other than where the cursor is.
20363 * @method setDragElPos
20364 * @param {int} iPageX the X coordinate of the mousedown or drag event
20365 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20367 setDragElPos: function(iPageX, iPageY) {
20368 // the first time we do this, we are going to check to make sure
20369 // the element has css positioning
20371 var el = this.getDragEl();
20372 this.alignElWithMouse(el, iPageX, iPageY);
20376 * Sets the element to the location of the mousedown or click event,
20377 * maintaining the cursor location relative to the location on the element
20378 * that was clicked. Override this if you want to place the element in a
20379 * location other than where the cursor is.
20380 * @method alignElWithMouse
20381 * @param {HTMLElement} el the element to move
20382 * @param {int} iPageX the X coordinate of the mousedown or drag event
20383 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20385 alignElWithMouse: function(el, iPageX, iPageY) {
20386 var oCoord = this.getTargetCoord(iPageX, iPageY);
20387 var fly = el.dom ? el : Roo.fly(el);
20388 if (!this.deltaSetXY) {
20389 var aCoord = [oCoord.x, oCoord.y];
20391 var newLeft = fly.getLeft(true);
20392 var newTop = fly.getTop(true);
20393 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20395 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20398 this.cachePosition(oCoord.x, oCoord.y);
20399 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20404 * Saves the most recent position so that we can reset the constraints and
20405 * tick marks on-demand. We need to know this so that we can calculate the
20406 * number of pixels the element is offset from its original position.
20407 * @method cachePosition
20408 * @param iPageX the current x position (optional, this just makes it so we
20409 * don't have to look it up again)
20410 * @param iPageY the current y position (optional, this just makes it so we
20411 * don't have to look it up again)
20413 cachePosition: function(iPageX, iPageY) {
20415 this.lastPageX = iPageX;
20416 this.lastPageY = iPageY;
20418 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20419 this.lastPageX = aCoord[0];
20420 this.lastPageY = aCoord[1];
20425 * Auto-scroll the window if the dragged object has been moved beyond the
20426 * visible window boundary.
20427 * @method autoScroll
20428 * @param {int} x the drag element's x position
20429 * @param {int} y the drag element's y position
20430 * @param {int} h the height of the drag element
20431 * @param {int} w the width of the drag element
20434 autoScroll: function(x, y, h, w) {
20437 // The client height
20438 var clientH = Roo.lib.Dom.getViewWidth();
20440 // The client width
20441 var clientW = Roo.lib.Dom.getViewHeight();
20443 // The amt scrolled down
20444 var st = this.DDM.getScrollTop();
20446 // The amt scrolled right
20447 var sl = this.DDM.getScrollLeft();
20449 // Location of the bottom of the element
20452 // Location of the right of the element
20455 // The distance from the cursor to the bottom of the visible area,
20456 // adjusted so that we don't scroll if the cursor is beyond the
20457 // element drag constraints
20458 var toBot = (clientH + st - y - this.deltaY);
20460 // The distance from the cursor to the right of the visible area
20461 var toRight = (clientW + sl - x - this.deltaX);
20464 // How close to the edge the cursor must be before we scroll
20465 // var thresh = (document.all) ? 100 : 40;
20468 // How many pixels to scroll per autoscroll op. This helps to reduce
20469 // clunky scrolling. IE is more sensitive about this ... it needs this
20470 // value to be higher.
20471 var scrAmt = (document.all) ? 80 : 30;
20473 // Scroll down if we are near the bottom of the visible page and the
20474 // obj extends below the crease
20475 if ( bot > clientH && toBot < thresh ) {
20476 window.scrollTo(sl, st + scrAmt);
20479 // Scroll up if the window is scrolled down and the top of the object
20480 // goes above the top border
20481 if ( y < st && st > 0 && y - st < thresh ) {
20482 window.scrollTo(sl, st - scrAmt);
20485 // Scroll right if the obj is beyond the right border and the cursor is
20486 // near the border.
20487 if ( right > clientW && toRight < thresh ) {
20488 window.scrollTo(sl + scrAmt, st);
20491 // Scroll left if the window has been scrolled to the right and the obj
20492 // extends past the left border
20493 if ( x < sl && sl > 0 && x - sl < thresh ) {
20494 window.scrollTo(sl - scrAmt, st);
20500 * Finds the location the element should be placed if we want to move
20501 * it to where the mouse location less the click offset would place us.
20502 * @method getTargetCoord
20503 * @param {int} iPageX the X coordinate of the click
20504 * @param {int} iPageY the Y coordinate of the click
20505 * @return an object that contains the coordinates (Object.x and Object.y)
20508 getTargetCoord: function(iPageX, iPageY) {
20511 var x = iPageX - this.deltaX;
20512 var y = iPageY - this.deltaY;
20514 if (this.constrainX) {
20515 if (x < this.minX) { x = this.minX; }
20516 if (x > this.maxX) { x = this.maxX; }
20519 if (this.constrainY) {
20520 if (y < this.minY) { y = this.minY; }
20521 if (y > this.maxY) { y = this.maxY; }
20524 x = this.getTick(x, this.xTicks);
20525 y = this.getTick(y, this.yTicks);
20532 * Sets up config options specific to this class. Overrides
20533 * Roo.dd.DragDrop, but all versions of this method through the
20534 * inheritance chain are called
20536 applyConfig: function() {
20537 Roo.dd.DD.superclass.applyConfig.call(this);
20538 this.scroll = (this.config.scroll !== false);
20542 * Event that fires prior to the onMouseDown event. Overrides
20545 b4MouseDown: function(e) {
20546 // this.resetConstraints();
20547 this.autoOffset(e.getPageX(),
20552 * Event that fires prior to the onDrag event. Overrides
20555 b4Drag: function(e) {
20556 this.setDragElPos(e.getPageX(),
20560 toString: function() {
20561 return ("DD " + this.id);
20564 //////////////////////////////////////////////////////////////////////////
20565 // Debugging ygDragDrop events that can be overridden
20566 //////////////////////////////////////////////////////////////////////////
20568 startDrag: function(x, y) {
20571 onDrag: function(e) {
20574 onDragEnter: function(e, id) {
20577 onDragOver: function(e, id) {
20580 onDragOut: function(e, id) {
20583 onDragDrop: function(e, id) {
20586 endDrag: function(e) {
20593 * Ext JS Library 1.1.1
20594 * Copyright(c) 2006-2007, Ext JS, LLC.
20596 * Originally Released Under LGPL - original licence link has changed is not relivant.
20599 * <script type="text/javascript">
20603 * @class Roo.dd.DDProxy
20604 * A DragDrop implementation that inserts an empty, bordered div into
20605 * the document that follows the cursor during drag operations. At the time of
20606 * the click, the frame div is resized to the dimensions of the linked html
20607 * element, and moved to the exact location of the linked element.
20609 * References to the "frame" element refer to the single proxy element that
20610 * was created to be dragged in place of all DDProxy elements on the
20613 * @extends Roo.dd.DD
20615 * @param {String} id the id of the linked html element
20616 * @param {String} sGroup the group of related DragDrop objects
20617 * @param {object} config an object containing configurable attributes
20618 * Valid properties for DDProxy in addition to those in DragDrop:
20619 * resizeFrame, centerFrame, dragElId
20621 Roo.dd.DDProxy = function(id, sGroup, config) {
20623 this.init(id, sGroup, config);
20629 * The default drag frame div id
20630 * @property Roo.dd.DDProxy.dragElId
20634 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20636 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20639 * By default we resize the drag frame to be the same size as the element
20640 * we want to drag (this is to get the frame effect). We can turn it off
20641 * if we want a different behavior.
20642 * @property resizeFrame
20648 * By default the frame is positioned exactly where the drag element is, so
20649 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20650 * you do not have constraints on the obj is to have the drag frame centered
20651 * around the cursor. Set centerFrame to true for this effect.
20652 * @property centerFrame
20655 centerFrame: false,
20658 * Creates the proxy element if it does not yet exist
20659 * @method createFrame
20661 createFrame: function() {
20663 var body = document.body;
20665 if (!body || !body.firstChild) {
20666 setTimeout( function() { self.createFrame(); }, 50 );
20670 var div = this.getDragEl();
20673 div = document.createElement("div");
20674 div.id = this.dragElId;
20677 s.position = "absolute";
20678 s.visibility = "hidden";
20680 s.border = "2px solid #aaa";
20683 // appendChild can blow up IE if invoked prior to the window load event
20684 // while rendering a table. It is possible there are other scenarios
20685 // that would cause this to happen as well.
20686 body.insertBefore(div, body.firstChild);
20691 * Initialization for the drag frame element. Must be called in the
20692 * constructor of all subclasses
20693 * @method initFrame
20695 initFrame: function() {
20696 this.createFrame();
20699 applyConfig: function() {
20700 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20702 this.resizeFrame = (this.config.resizeFrame !== false);
20703 this.centerFrame = (this.config.centerFrame);
20704 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20708 * Resizes the drag frame to the dimensions of the clicked object, positions
20709 * it over the object, and finally displays it
20710 * @method showFrame
20711 * @param {int} iPageX X click position
20712 * @param {int} iPageY Y click position
20715 showFrame: function(iPageX, iPageY) {
20716 var el = this.getEl();
20717 var dragEl = this.getDragEl();
20718 var s = dragEl.style;
20720 this._resizeProxy();
20722 if (this.centerFrame) {
20723 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20724 Math.round(parseInt(s.height, 10)/2) );
20727 this.setDragElPos(iPageX, iPageY);
20729 Roo.fly(dragEl).show();
20733 * The proxy is automatically resized to the dimensions of the linked
20734 * element when a drag is initiated, unless resizeFrame is set to false
20735 * @method _resizeProxy
20738 _resizeProxy: function() {
20739 if (this.resizeFrame) {
20740 var el = this.getEl();
20741 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20745 // overrides Roo.dd.DragDrop
20746 b4MouseDown: function(e) {
20747 var x = e.getPageX();
20748 var y = e.getPageY();
20749 this.autoOffset(x, y);
20750 this.setDragElPos(x, y);
20753 // overrides Roo.dd.DragDrop
20754 b4StartDrag: function(x, y) {
20755 // show the drag frame
20756 this.showFrame(x, y);
20759 // overrides Roo.dd.DragDrop
20760 b4EndDrag: function(e) {
20761 Roo.fly(this.getDragEl()).hide();
20764 // overrides Roo.dd.DragDrop
20765 // By default we try to move the element to the last location of the frame.
20766 // This is so that the default behavior mirrors that of Roo.dd.DD.
20767 endDrag: function(e) {
20769 var lel = this.getEl();
20770 var del = this.getDragEl();
20772 // Show the drag frame briefly so we can get its position
20773 del.style.visibility = "";
20776 // Hide the linked element before the move to get around a Safari
20778 lel.style.visibility = "hidden";
20779 Roo.dd.DDM.moveToEl(lel, del);
20780 del.style.visibility = "hidden";
20781 lel.style.visibility = "";
20786 beforeMove : function(){
20790 afterDrag : function(){
20794 toString: function() {
20795 return ("DDProxy " + this.id);
20801 * Ext JS Library 1.1.1
20802 * Copyright(c) 2006-2007, Ext JS, LLC.
20804 * Originally Released Under LGPL - original licence link has changed is not relivant.
20807 * <script type="text/javascript">
20811 * @class Roo.dd.DDTarget
20812 * A DragDrop implementation that does not move, but can be a drop
20813 * target. You would get the same result by simply omitting implementation
20814 * for the event callbacks, but this way we reduce the processing cost of the
20815 * event listener and the callbacks.
20816 * @extends Roo.dd.DragDrop
20818 * @param {String} id the id of the element that is a drop target
20819 * @param {String} sGroup the group of related DragDrop objects
20820 * @param {object} config an object containing configurable attributes
20821 * Valid properties for DDTarget in addition to those in
20825 Roo.dd.DDTarget = function(id, sGroup, config) {
20827 this.initTarget(id, sGroup, config);
20829 if (config.listeners || config.events) {
20830 Roo.dd.DragDrop.superclass.constructor.call(this, {
20831 listeners : config.listeners || {},
20832 events : config.events || {}
20837 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20838 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20839 toString: function() {
20840 return ("DDTarget " + this.id);
20845 * Ext JS Library 1.1.1
20846 * Copyright(c) 2006-2007, Ext JS, LLC.
20848 * Originally Released Under LGPL - original licence link has changed is not relivant.
20851 * <script type="text/javascript">
20856 * @class Roo.dd.ScrollManager
20857 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20858 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20861 Roo.dd.ScrollManager = function(){
20862 var ddm = Roo.dd.DragDropMgr;
20869 var onStop = function(e){
20874 var triggerRefresh = function(){
20875 if(ddm.dragCurrent){
20876 ddm.refreshCache(ddm.dragCurrent.groups);
20880 var doScroll = function(){
20881 if(ddm.dragCurrent){
20882 var dds = Roo.dd.ScrollManager;
20884 if(proc.el.scroll(proc.dir, dds.increment)){
20888 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
20893 var clearProc = function(){
20895 clearInterval(proc.id);
20902 var startProc = function(el, dir){
20903 Roo.log('scroll startproc');
20907 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
20910 var onFire = function(e, isDrop){
20912 if(isDrop || !ddm.dragCurrent){ return; }
20913 var dds = Roo.dd.ScrollManager;
20914 if(!dragEl || dragEl != ddm.dragCurrent){
20915 dragEl = ddm.dragCurrent;
20916 // refresh regions on drag start
20917 dds.refreshCache();
20920 var xy = Roo.lib.Event.getXY(e);
20921 var pt = new Roo.lib.Point(xy[0], xy[1]);
20922 for(var id in els){
20923 var el = els[id], r = el._region;
20924 if(r && r.contains(pt) && el.isScrollable()){
20925 if(r.bottom - pt.y <= dds.thresh){
20927 startProc(el, "down");
20930 }else if(r.right - pt.x <= dds.thresh){
20932 startProc(el, "left");
20935 }else if(pt.y - r.top <= dds.thresh){
20937 startProc(el, "up");
20940 }else if(pt.x - r.left <= dds.thresh){
20942 startProc(el, "right");
20951 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
20952 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
20956 * Registers new overflow element(s) to auto scroll
20957 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
20959 register : function(el){
20960 if(el instanceof Array){
20961 for(var i = 0, len = el.length; i < len; i++) {
20962 this.register(el[i]);
20968 Roo.dd.ScrollManager.els = els;
20972 * Unregisters overflow element(s) so they are no longer scrolled
20973 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
20975 unregister : function(el){
20976 if(el instanceof Array){
20977 for(var i = 0, len = el.length; i < len; i++) {
20978 this.unregister(el[i]);
20987 * The number of pixels from the edge of a container the pointer needs to be to
20988 * trigger scrolling (defaults to 25)
20994 * The number of pixels to scroll in each scroll increment (defaults to 50)
21000 * The frequency of scrolls in milliseconds (defaults to 500)
21006 * True to animate the scroll (defaults to true)
21012 * The animation duration in seconds -
21013 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21019 * Manually trigger a cache refresh.
21021 refreshCache : function(){
21022 for(var id in els){
21023 if(typeof els[id] == 'object'){ // for people extending the object prototype
21024 els[id]._region = els[id].getRegion();
21031 * Ext JS Library 1.1.1
21032 * Copyright(c) 2006-2007, Ext JS, LLC.
21034 * Originally Released Under LGPL - original licence link has changed is not relivant.
21037 * <script type="text/javascript">
21042 * @class Roo.dd.Registry
21043 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21044 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21047 Roo.dd.Registry = function(){
21050 var autoIdSeed = 0;
21052 var getId = function(el, autogen){
21053 if(typeof el == "string"){
21057 if(!id && autogen !== false){
21058 id = "roodd-" + (++autoIdSeed);
21066 * Register a drag drop element
21067 * @param {String|HTMLElement} element The id or DOM node to register
21068 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21069 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21070 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21071 * populated in the data object (if applicable):
21073 Value Description<br />
21074 --------- ------------------------------------------<br />
21075 handles Array of DOM nodes that trigger dragging<br />
21076 for the element being registered<br />
21077 isHandle True if the element passed in triggers<br />
21078 dragging itself, else false
21081 register : function(el, data){
21083 if(typeof el == "string"){
21084 el = document.getElementById(el);
21087 elements[getId(el)] = data;
21088 if(data.isHandle !== false){
21089 handles[data.ddel.id] = data;
21092 var hs = data.handles;
21093 for(var i = 0, len = hs.length; i < len; i++){
21094 handles[getId(hs[i])] = data;
21100 * Unregister a drag drop element
21101 * @param {String|HTMLElement} element The id or DOM node to unregister
21103 unregister : function(el){
21104 var id = getId(el, false);
21105 var data = elements[id];
21107 delete elements[id];
21109 var hs = data.handles;
21110 for(var i = 0, len = hs.length; i < len; i++){
21111 delete handles[getId(hs[i], false)];
21118 * Returns the handle registered for a DOM Node by id
21119 * @param {String|HTMLElement} id The DOM node or id to look up
21120 * @return {Object} handle The custom handle data
21122 getHandle : function(id){
21123 if(typeof id != "string"){ // must be element?
21126 return handles[id];
21130 * Returns the handle that is registered for the DOM node that is the target of the event
21131 * @param {Event} e The event
21132 * @return {Object} handle The custom handle data
21134 getHandleFromEvent : function(e){
21135 var t = Roo.lib.Event.getTarget(e);
21136 return t ? handles[t.id] : null;
21140 * Returns a custom data object that is registered for a DOM node by id
21141 * @param {String|HTMLElement} id The DOM node or id to look up
21142 * @return {Object} data The custom data
21144 getTarget : function(id){
21145 if(typeof id != "string"){ // must be element?
21148 return elements[id];
21152 * Returns a custom data object that is registered for the DOM node that is the target of the event
21153 * @param {Event} e The event
21154 * @return {Object} data The custom data
21156 getTargetFromEvent : function(e){
21157 var t = Roo.lib.Event.getTarget(e);
21158 return t ? elements[t.id] || handles[t.id] : null;
21163 * Ext JS Library 1.1.1
21164 * Copyright(c) 2006-2007, Ext JS, LLC.
21166 * Originally Released Under LGPL - original licence link has changed is not relivant.
21169 * <script type="text/javascript">
21174 * @class Roo.dd.StatusProxy
21175 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21176 * default drag proxy used by all Roo.dd components.
21178 * @param {Object} config
21180 Roo.dd.StatusProxy = function(config){
21181 Roo.apply(this, config);
21182 this.id = this.id || Roo.id();
21183 this.el = new Roo.Layer({
21185 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21186 {tag: "div", cls: "x-dd-drop-icon"},
21187 {tag: "div", cls: "x-dd-drag-ghost"}
21190 shadow: !config || config.shadow !== false
21192 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21193 this.dropStatus = this.dropNotAllowed;
21196 Roo.dd.StatusProxy.prototype = {
21198 * @cfg {String} dropAllowed
21199 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21201 dropAllowed : "x-dd-drop-ok",
21203 * @cfg {String} dropNotAllowed
21204 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21206 dropNotAllowed : "x-dd-drop-nodrop",
21209 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21210 * over the current target element.
21211 * @param {String} cssClass The css class for the new drop status indicator image
21213 setStatus : function(cssClass){
21214 cssClass = cssClass || this.dropNotAllowed;
21215 if(this.dropStatus != cssClass){
21216 this.el.replaceClass(this.dropStatus, cssClass);
21217 this.dropStatus = cssClass;
21222 * Resets the status indicator to the default dropNotAllowed value
21223 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21225 reset : function(clearGhost){
21226 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21227 this.dropStatus = this.dropNotAllowed;
21229 this.ghost.update("");
21234 * Updates the contents of the ghost element
21235 * @param {String} html The html that will replace the current innerHTML of the ghost element
21237 update : function(html){
21238 if(typeof html == "string"){
21239 this.ghost.update(html);
21241 this.ghost.update("");
21242 html.style.margin = "0";
21243 this.ghost.dom.appendChild(html);
21245 // ensure float = none set?? cant remember why though.
21246 var el = this.ghost.dom.firstChild;
21248 Roo.fly(el).setStyle('float', 'none');
21253 * Returns the underlying proxy {@link Roo.Layer}
21254 * @return {Roo.Layer} el
21256 getEl : function(){
21261 * Returns the ghost element
21262 * @return {Roo.Element} el
21264 getGhost : function(){
21270 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21272 hide : function(clear){
21280 * Stops the repair animation if it's currently running
21283 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21289 * Displays this proxy
21296 * Force the Layer to sync its shadow and shim positions to the element
21303 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21304 * invalid drop operation by the item being dragged.
21305 * @param {Array} xy The XY position of the element ([x, y])
21306 * @param {Function} callback The function to call after the repair is complete
21307 * @param {Object} scope The scope in which to execute the callback
21309 repair : function(xy, callback, scope){
21310 this.callback = callback;
21311 this.scope = scope;
21312 if(xy && this.animRepair !== false){
21313 this.el.addClass("x-dd-drag-repair");
21314 this.el.hideUnders(true);
21315 this.anim = this.el.shift({
21316 duration: this.repairDuration || .5,
21320 callback: this.afterRepair,
21324 this.afterRepair();
21329 afterRepair : function(){
21331 if(typeof this.callback == "function"){
21332 this.callback.call(this.scope || this);
21334 this.callback = null;
21339 * Ext JS Library 1.1.1
21340 * Copyright(c) 2006-2007, Ext JS, LLC.
21342 * Originally Released Under LGPL - original licence link has changed is not relivant.
21345 * <script type="text/javascript">
21349 * @class Roo.dd.DragSource
21350 * @extends Roo.dd.DDProxy
21351 * A simple class that provides the basic implementation needed to make any element draggable.
21353 * @param {String/HTMLElement/Element} el The container element
21354 * @param {Object} config
21356 Roo.dd.DragSource = function(el, config){
21357 this.el = Roo.get(el);
21358 this.dragData = {};
21360 Roo.apply(this, config);
21363 this.proxy = new Roo.dd.StatusProxy();
21366 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21367 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21369 this.dragging = false;
21372 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21374 * @cfg {String} dropAllowed
21375 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21377 dropAllowed : "x-dd-drop-ok",
21379 * @cfg {String} dropNotAllowed
21380 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21382 dropNotAllowed : "x-dd-drop-nodrop",
21385 * Returns the data object associated with this drag source
21386 * @return {Object} data An object containing arbitrary data
21388 getDragData : function(e){
21389 return this.dragData;
21393 onDragEnter : function(e, id){
21394 var target = Roo.dd.DragDropMgr.getDDById(id);
21395 this.cachedTarget = target;
21396 if(this.beforeDragEnter(target, e, id) !== false){
21397 if(target.isNotifyTarget){
21398 var status = target.notifyEnter(this, e, this.dragData);
21399 this.proxy.setStatus(status);
21401 this.proxy.setStatus(this.dropAllowed);
21404 if(this.afterDragEnter){
21406 * An empty function by default, but provided so that you can perform a custom action
21407 * when the dragged item enters the drop target by providing an implementation.
21408 * @param {Roo.dd.DragDrop} target The drop target
21409 * @param {Event} e The event object
21410 * @param {String} id The id of the dragged element
21411 * @method afterDragEnter
21413 this.afterDragEnter(target, e, id);
21419 * An empty function by default, but provided so that you can perform a custom action
21420 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21421 * @param {Roo.dd.DragDrop} target The drop target
21422 * @param {Event} e The event object
21423 * @param {String} id The id of the dragged element
21424 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21426 beforeDragEnter : function(target, e, id){
21431 alignElWithMouse: function() {
21432 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21437 onDragOver : function(e, id){
21438 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21439 if(this.beforeDragOver(target, e, id) !== false){
21440 if(target.isNotifyTarget){
21441 var status = target.notifyOver(this, e, this.dragData);
21442 this.proxy.setStatus(status);
21445 if(this.afterDragOver){
21447 * An empty function by default, but provided so that you can perform a custom action
21448 * while the dragged item is over the drop target by providing an implementation.
21449 * @param {Roo.dd.DragDrop} target The drop target
21450 * @param {Event} e The event object
21451 * @param {String} id The id of the dragged element
21452 * @method afterDragOver
21454 this.afterDragOver(target, e, id);
21460 * An empty function by default, but provided so that you can perform a custom action
21461 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21462 * @param {Roo.dd.DragDrop} target The drop target
21463 * @param {Event} e The event object
21464 * @param {String} id The id of the dragged element
21465 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21467 beforeDragOver : function(target, e, id){
21472 onDragOut : function(e, id){
21473 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21474 if(this.beforeDragOut(target, e, id) !== false){
21475 if(target.isNotifyTarget){
21476 target.notifyOut(this, e, this.dragData);
21478 this.proxy.reset();
21479 if(this.afterDragOut){
21481 * An empty function by default, but provided so that you can perform a custom action
21482 * after the dragged item is dragged out of the target without dropping.
21483 * @param {Roo.dd.DragDrop} target The drop target
21484 * @param {Event} e The event object
21485 * @param {String} id The id of the dragged element
21486 * @method afterDragOut
21488 this.afterDragOut(target, e, id);
21491 this.cachedTarget = null;
21495 * An empty function by default, but provided so that you can perform a custom action before the dragged
21496 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21497 * @param {Roo.dd.DragDrop} target The drop target
21498 * @param {Event} e The event object
21499 * @param {String} id The id of the dragged element
21500 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21502 beforeDragOut : function(target, e, id){
21507 onDragDrop : function(e, id){
21508 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21509 if(this.beforeDragDrop(target, e, id) !== false){
21510 if(target.isNotifyTarget){
21511 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21512 this.onValidDrop(target, e, id);
21514 this.onInvalidDrop(target, e, id);
21517 this.onValidDrop(target, e, id);
21520 if(this.afterDragDrop){
21522 * An empty function by default, but provided so that you can perform a custom action
21523 * after a valid drag drop has occurred by providing an implementation.
21524 * @param {Roo.dd.DragDrop} target The drop target
21525 * @param {Event} e The event object
21526 * @param {String} id The id of the dropped element
21527 * @method afterDragDrop
21529 this.afterDragDrop(target, e, id);
21532 delete this.cachedTarget;
21536 * An empty function by default, but provided so that you can perform a custom action before the dragged
21537 * item is dropped onto the target and optionally cancel the onDragDrop.
21538 * @param {Roo.dd.DragDrop} target The drop target
21539 * @param {Event} e The event object
21540 * @param {String} id The id of the dragged element
21541 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21543 beforeDragDrop : function(target, e, id){
21548 onValidDrop : function(target, e, id){
21550 if(this.afterValidDrop){
21552 * An empty function by default, but provided so that you can perform a custom action
21553 * after a valid drop has occurred by providing an implementation.
21554 * @param {Object} target The target DD
21555 * @param {Event} e The event object
21556 * @param {String} id The id of the dropped element
21557 * @method afterInvalidDrop
21559 this.afterValidDrop(target, e, id);
21564 getRepairXY : function(e, data){
21565 return this.el.getXY();
21569 onInvalidDrop : function(target, e, id){
21570 this.beforeInvalidDrop(target, e, id);
21571 if(this.cachedTarget){
21572 if(this.cachedTarget.isNotifyTarget){
21573 this.cachedTarget.notifyOut(this, e, this.dragData);
21575 this.cacheTarget = null;
21577 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21579 if(this.afterInvalidDrop){
21581 * An empty function by default, but provided so that you can perform a custom action
21582 * after an invalid drop has occurred by providing an implementation.
21583 * @param {Event} e The event object
21584 * @param {String} id The id of the dropped element
21585 * @method afterInvalidDrop
21587 this.afterInvalidDrop(e, id);
21592 afterRepair : function(){
21594 this.el.highlight(this.hlColor || "c3daf9");
21596 this.dragging = false;
21600 * An empty function by default, but provided so that you can perform a custom action after an invalid
21601 * drop has occurred.
21602 * @param {Roo.dd.DragDrop} target The drop target
21603 * @param {Event} e The event object
21604 * @param {String} id The id of the dragged element
21605 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21607 beforeInvalidDrop : function(target, e, id){
21612 handleMouseDown : function(e){
21613 if(this.dragging) {
21616 var data = this.getDragData(e);
21617 if(data && this.onBeforeDrag(data, e) !== false){
21618 this.dragData = data;
21620 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21625 * An empty function by default, but provided so that you can perform a custom action before the initial
21626 * drag event begins and optionally cancel it.
21627 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21628 * @param {Event} e The event object
21629 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21631 onBeforeDrag : function(data, e){
21636 * An empty function by default, but provided so that you can perform a custom action once the initial
21637 * drag event has begun. The drag cannot be canceled from this function.
21638 * @param {Number} x The x position of the click on the dragged object
21639 * @param {Number} y The y position of the click on the dragged object
21641 onStartDrag : Roo.emptyFn,
21643 // private - YUI override
21644 startDrag : function(x, y){
21645 this.proxy.reset();
21646 this.dragging = true;
21647 this.proxy.update("");
21648 this.onInitDrag(x, y);
21653 onInitDrag : function(x, y){
21654 var clone = this.el.dom.cloneNode(true);
21655 clone.id = Roo.id(); // prevent duplicate ids
21656 this.proxy.update(clone);
21657 this.onStartDrag(x, y);
21662 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21663 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21665 getProxy : function(){
21670 * Hides the drag source's {@link Roo.dd.StatusProxy}
21672 hideProxy : function(){
21674 this.proxy.reset(true);
21675 this.dragging = false;
21679 triggerCacheRefresh : function(){
21680 Roo.dd.DDM.refreshCache(this.groups);
21683 // private - override to prevent hiding
21684 b4EndDrag: function(e) {
21687 // private - override to prevent moving
21688 endDrag : function(e){
21689 this.onEndDrag(this.dragData, e);
21693 onEndDrag : function(data, e){
21696 // private - pin to cursor
21697 autoOffset : function(x, y) {
21698 this.setDelta(-12, -20);
21702 * Ext JS Library 1.1.1
21703 * Copyright(c) 2006-2007, Ext JS, LLC.
21705 * Originally Released Under LGPL - original licence link has changed is not relivant.
21708 * <script type="text/javascript">
21713 * @class Roo.dd.DropTarget
21714 * @extends Roo.dd.DDTarget
21715 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21716 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21718 * @param {String/HTMLElement/Element} el The container element
21719 * @param {Object} config
21721 Roo.dd.DropTarget = function(el, config){
21722 this.el = Roo.get(el);
21724 var listeners = false; ;
21725 if (config && config.listeners) {
21726 listeners= config.listeners;
21727 delete config.listeners;
21729 Roo.apply(this, config);
21731 if(this.containerScroll){
21732 Roo.dd.ScrollManager.register(this.el);
21736 * @scope Roo.dd.DropTarget
21741 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21742 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21743 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21745 * IMPORTANT : it should set this.overClass and this.dropAllowed
21747 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21748 * @param {Event} e The event
21749 * @param {Object} data An object containing arbitrary data supplied by the drag source
21755 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21756 * This method will be called on every mouse movement while the drag source is over the drop target.
21757 * This default implementation simply returns the dropAllowed config value.
21759 * IMPORTANT : it should set this.dropAllowed
21761 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21762 * @param {Event} e The event
21763 * @param {Object} data An object containing arbitrary data supplied by the drag source
21769 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21770 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21771 * overClass (if any) from the drop element.
21773 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21774 * @param {Event} e The event
21775 * @param {Object} data An object containing arbitrary data supplied by the drag source
21781 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21782 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21783 * implementation that does something to process the drop event and returns true so that the drag source's
21784 * repair action does not run.
21786 * IMPORTANT : it should set this.success
21788 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21789 * @param {Event} e The event
21790 * @param {Object} data An object containing arbitrary data supplied by the drag source
21796 Roo.dd.DropTarget.superclass.constructor.call( this,
21798 this.ddGroup || this.group,
21801 listeners : listeners || {}
21809 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21811 * @cfg {String} overClass
21812 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21815 * @cfg {String} ddGroup
21816 * The drag drop group to handle drop events for
21820 * @cfg {String} dropAllowed
21821 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21823 dropAllowed : "x-dd-drop-ok",
21825 * @cfg {String} dropNotAllowed
21826 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21828 dropNotAllowed : "x-dd-drop-nodrop",
21830 * @cfg {boolean} success
21831 * set this after drop listener..
21835 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21836 * if the drop point is valid for over/enter..
21843 isNotifyTarget : true,
21848 notifyEnter : function(dd, e, data)
21851 this.fireEvent('enter', dd, e, data);
21852 if(this.overClass){
21853 this.el.addClass(this.overClass);
21855 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21856 this.valid ? this.dropAllowed : this.dropNotAllowed
21863 notifyOver : function(dd, e, data)
21866 this.fireEvent('over', dd, e, data);
21867 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21868 this.valid ? this.dropAllowed : this.dropNotAllowed
21875 notifyOut : function(dd, e, data)
21877 this.fireEvent('out', dd, e, data);
21878 if(this.overClass){
21879 this.el.removeClass(this.overClass);
21886 notifyDrop : function(dd, e, data)
21888 this.success = false;
21889 this.fireEvent('drop', dd, e, data);
21890 return this.success;
21894 * Ext JS Library 1.1.1
21895 * Copyright(c) 2006-2007, Ext JS, LLC.
21897 * Originally Released Under LGPL - original licence link has changed is not relivant.
21900 * <script type="text/javascript">
21905 * @class Roo.dd.DragZone
21906 * @extends Roo.dd.DragSource
21907 * This class provides a container DD instance that proxies for multiple child node sources.<br />
21908 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
21910 * @param {String/HTMLElement/Element} el The container element
21911 * @param {Object} config
21913 Roo.dd.DragZone = function(el, config){
21914 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
21915 if(this.containerScroll){
21916 Roo.dd.ScrollManager.register(this.el);
21920 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
21922 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
21923 * for auto scrolling during drag operations.
21926 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
21927 * method after a failed drop (defaults to "c3daf9" - light blue)
21931 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
21932 * for a valid target to drag based on the mouse down. Override this method
21933 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
21934 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
21935 * @param {EventObject} e The mouse down event
21936 * @return {Object} The dragData
21938 getDragData : function(e){
21939 return Roo.dd.Registry.getHandleFromEvent(e);
21943 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
21944 * this.dragData.ddel
21945 * @param {Number} x The x position of the click on the dragged object
21946 * @param {Number} y The y position of the click on the dragged object
21947 * @return {Boolean} true to continue the drag, false to cancel
21949 onInitDrag : function(x, y){
21950 this.proxy.update(this.dragData.ddel.cloneNode(true));
21951 this.onStartDrag(x, y);
21956 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
21958 afterRepair : function(){
21960 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
21962 this.dragging = false;
21966 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
21967 * the XY of this.dragData.ddel
21968 * @param {EventObject} e The mouse up event
21969 * @return {Array} The xy location (e.g. [100, 200])
21971 getRepairXY : function(e){
21972 return Roo.Element.fly(this.dragData.ddel).getXY();
21976 * Ext JS Library 1.1.1
21977 * Copyright(c) 2006-2007, Ext JS, LLC.
21979 * Originally Released Under LGPL - original licence link has changed is not relivant.
21982 * <script type="text/javascript">
21985 * @class Roo.dd.DropZone
21986 * @extends Roo.dd.DropTarget
21987 * This class provides a container DD instance that proxies for multiple child node targets.<br />
21988 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
21990 * @param {String/HTMLElement/Element} el The container element
21991 * @param {Object} config
21993 Roo.dd.DropZone = function(el, config){
21994 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
21997 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
21999 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22000 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22001 * provide your own custom lookup.
22002 * @param {Event} e The event
22003 * @return {Object} data The custom data
22005 getTargetFromEvent : function(e){
22006 return Roo.dd.Registry.getTargetFromEvent(e);
22010 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22011 * that it has registered. This method has no default implementation and should be overridden to provide
22012 * node-specific processing if necessary.
22013 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22014 * {@link #getTargetFromEvent} for this node)
22015 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22016 * @param {Event} e The event
22017 * @param {Object} data An object containing arbitrary data supplied by the drag source
22019 onNodeEnter : function(n, dd, e, data){
22024 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22025 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22026 * overridden to provide the proper feedback.
22027 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22028 * {@link #getTargetFromEvent} for this node)
22029 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22030 * @param {Event} e The event
22031 * @param {Object} data An object containing arbitrary data supplied by the drag source
22032 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22033 * underlying {@link Roo.dd.StatusProxy} can be updated
22035 onNodeOver : function(n, dd, e, data){
22036 return this.dropAllowed;
22040 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22041 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22042 * node-specific processing if necessary.
22043 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22044 * {@link #getTargetFromEvent} for this node)
22045 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22046 * @param {Event} e The event
22047 * @param {Object} data An object containing arbitrary data supplied by the drag source
22049 onNodeOut : function(n, dd, e, data){
22054 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22055 * the drop node. The default implementation returns false, so it should be overridden to provide the
22056 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22057 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22058 * {@link #getTargetFromEvent} for this node)
22059 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22060 * @param {Event} e The event
22061 * @param {Object} data An object containing arbitrary data supplied by the drag source
22062 * @return {Boolean} True if the drop was valid, else false
22064 onNodeDrop : function(n, dd, e, data){
22069 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22070 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22071 * it should be overridden to provide the proper feedback if necessary.
22072 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22073 * @param {Event} e The event
22074 * @param {Object} data An object containing arbitrary data supplied by the drag source
22075 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22076 * underlying {@link Roo.dd.StatusProxy} can be updated
22078 onContainerOver : function(dd, e, data){
22079 return this.dropNotAllowed;
22083 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22084 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22085 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22086 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22087 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22088 * @param {Event} e The event
22089 * @param {Object} data An object containing arbitrary data supplied by the drag source
22090 * @return {Boolean} True if the drop was valid, else false
22092 onContainerDrop : function(dd, e, data){
22097 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22098 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22099 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22100 * you should override this method and provide a custom implementation.
22101 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22102 * @param {Event} e The event
22103 * @param {Object} data An object containing arbitrary data supplied by the drag source
22104 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22105 * underlying {@link Roo.dd.StatusProxy} can be updated
22107 notifyEnter : function(dd, e, data){
22108 return this.dropNotAllowed;
22112 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22113 * This method will be called on every mouse movement while the drag source is over the drop zone.
22114 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22115 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22116 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22117 * registered node, it will call {@link #onContainerOver}.
22118 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22119 * @param {Event} e The event
22120 * @param {Object} data An object containing arbitrary data supplied by the drag source
22121 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22122 * underlying {@link Roo.dd.StatusProxy} can be updated
22124 notifyOver : function(dd, e, data){
22125 var n = this.getTargetFromEvent(e);
22126 if(!n){ // not over valid drop target
22127 if(this.lastOverNode){
22128 this.onNodeOut(this.lastOverNode, dd, e, data);
22129 this.lastOverNode = null;
22131 return this.onContainerOver(dd, e, data);
22133 if(this.lastOverNode != n){
22134 if(this.lastOverNode){
22135 this.onNodeOut(this.lastOverNode, dd, e, data);
22137 this.onNodeEnter(n, dd, e, data);
22138 this.lastOverNode = n;
22140 return this.onNodeOver(n, dd, e, data);
22144 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22145 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22146 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22147 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22148 * @param {Event} e The event
22149 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22151 notifyOut : function(dd, e, data){
22152 if(this.lastOverNode){
22153 this.onNodeOut(this.lastOverNode, dd, e, data);
22154 this.lastOverNode = null;
22159 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22160 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22161 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22162 * otherwise it will call {@link #onContainerDrop}.
22163 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22164 * @param {Event} e The event
22165 * @param {Object} data An object containing arbitrary data supplied by the drag source
22166 * @return {Boolean} True if the drop was valid, else false
22168 notifyDrop : function(dd, e, data){
22169 if(this.lastOverNode){
22170 this.onNodeOut(this.lastOverNode, dd, e, data);
22171 this.lastOverNode = null;
22173 var n = this.getTargetFromEvent(e);
22175 this.onNodeDrop(n, dd, e, data) :
22176 this.onContainerDrop(dd, e, data);
22180 triggerCacheRefresh : function(){
22181 Roo.dd.DDM.refreshCache(this.groups);
22185 * Ext JS Library 1.1.1
22186 * Copyright(c) 2006-2007, Ext JS, LLC.
22188 * Originally Released Under LGPL - original licence link has changed is not relivant.
22191 * <script type="text/javascript">
22196 * @class Roo.data.SortTypes
22198 * Defines the default sorting (casting?) comparison functions used when sorting data.
22200 Roo.data.SortTypes = {
22202 * Default sort that does nothing
22203 * @param {Mixed} s The value being converted
22204 * @return {Mixed} The comparison value
22206 none : function(s){
22211 * The regular expression used to strip tags
22215 stripTagsRE : /<\/?[^>]+>/gi,
22218 * Strips all HTML tags to sort on text only
22219 * @param {Mixed} s The value being converted
22220 * @return {String} The comparison value
22222 asText : function(s){
22223 return String(s).replace(this.stripTagsRE, "");
22227 * Strips all HTML tags to sort on text only - Case insensitive
22228 * @param {Mixed} s The value being converted
22229 * @return {String} The comparison value
22231 asUCText : function(s){
22232 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22236 * Case insensitive string
22237 * @param {Mixed} s The value being converted
22238 * @return {String} The comparison value
22240 asUCString : function(s) {
22241 return String(s).toUpperCase();
22246 * @param {Mixed} s The value being converted
22247 * @return {Number} The comparison value
22249 asDate : function(s) {
22253 if(s instanceof Date){
22254 return s.getTime();
22256 return Date.parse(String(s));
22261 * @param {Mixed} s The value being converted
22262 * @return {Float} The comparison value
22264 asFloat : function(s) {
22265 var val = parseFloat(String(s).replace(/,/g, ""));
22274 * @param {Mixed} s The value being converted
22275 * @return {Number} The comparison value
22277 asInt : function(s) {
22278 var val = parseInt(String(s).replace(/,/g, ""));
22286 * Ext JS Library 1.1.1
22287 * Copyright(c) 2006-2007, Ext JS, LLC.
22289 * Originally Released Under LGPL - original licence link has changed is not relivant.
22292 * <script type="text/javascript">
22296 * @class Roo.data.Record
22297 * Instances of this class encapsulate both record <em>definition</em> information, and record
22298 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22299 * to access Records cached in an {@link Roo.data.Store} object.<br>
22301 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22302 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22305 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22307 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22308 * {@link #create}. The parameters are the same.
22309 * @param {Array} data An associative Array of data values keyed by the field name.
22310 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22311 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22312 * not specified an integer id is generated.
22314 Roo.data.Record = function(data, id){
22315 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22320 * Generate a constructor for a specific record layout.
22321 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22322 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22323 * Each field definition object may contain the following properties: <ul>
22324 * <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,
22325 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22326 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22327 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22328 * is being used, then this is a string containing the javascript expression to reference the data relative to
22329 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22330 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22331 * this may be omitted.</p></li>
22332 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22333 * <ul><li>auto (Default, implies no conversion)</li>
22338 * <li>date</li></ul></p></li>
22339 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22340 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22341 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22342 * by the Reader into an object that will be stored in the Record. It is passed the
22343 * following parameters:<ul>
22344 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22346 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22348 * <br>usage:<br><pre><code>
22349 var TopicRecord = Roo.data.Record.create(
22350 {name: 'title', mapping: 'topic_title'},
22351 {name: 'author', mapping: 'username'},
22352 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22353 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22354 {name: 'lastPoster', mapping: 'user2'},
22355 {name: 'excerpt', mapping: 'post_text'}
22358 var myNewRecord = new TopicRecord({
22359 title: 'Do my job please',
22362 lastPost: new Date(),
22363 lastPoster: 'Animal',
22364 excerpt: 'No way dude!'
22366 myStore.add(myNewRecord);
22371 Roo.data.Record.create = function(o){
22372 var f = function(){
22373 f.superclass.constructor.apply(this, arguments);
22375 Roo.extend(f, Roo.data.Record);
22376 var p = f.prototype;
22377 p.fields = new Roo.util.MixedCollection(false, function(field){
22380 for(var i = 0, len = o.length; i < len; i++){
22381 p.fields.add(new Roo.data.Field(o[i]));
22383 f.getField = function(name){
22384 return p.fields.get(name);
22389 Roo.data.Record.AUTO_ID = 1000;
22390 Roo.data.Record.EDIT = 'edit';
22391 Roo.data.Record.REJECT = 'reject';
22392 Roo.data.Record.COMMIT = 'commit';
22394 Roo.data.Record.prototype = {
22396 * Readonly flag - true if this record has been modified.
22405 join : function(store){
22406 this.store = store;
22410 * Set the named field to the specified value.
22411 * @param {String} name The name of the field to set.
22412 * @param {Object} value The value to set the field to.
22414 set : function(name, value){
22415 if(this.data[name] == value){
22419 if(!this.modified){
22420 this.modified = {};
22422 if(typeof this.modified[name] == 'undefined'){
22423 this.modified[name] = this.data[name];
22425 this.data[name] = value;
22426 if(!this.editing && this.store){
22427 this.store.afterEdit(this);
22432 * Get the value of the named field.
22433 * @param {String} name The name of the field to get the value of.
22434 * @return {Object} The value of the field.
22436 get : function(name){
22437 return this.data[name];
22441 beginEdit : function(){
22442 this.editing = true;
22443 this.modified = {};
22447 cancelEdit : function(){
22448 this.editing = false;
22449 delete this.modified;
22453 endEdit : function(){
22454 this.editing = false;
22455 if(this.dirty && this.store){
22456 this.store.afterEdit(this);
22461 * Usually called by the {@link Roo.data.Store} which owns the Record.
22462 * Rejects all changes made to the Record since either creation, or the last commit operation.
22463 * Modified fields are reverted to their original values.
22465 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22466 * of reject operations.
22468 reject : function(){
22469 var m = this.modified;
22471 if(typeof m[n] != "function"){
22472 this.data[n] = m[n];
22475 this.dirty = false;
22476 delete this.modified;
22477 this.editing = false;
22479 this.store.afterReject(this);
22484 * Usually called by the {@link Roo.data.Store} which owns the Record.
22485 * Commits all changes made to the Record since either creation, or the last commit operation.
22487 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22488 * of commit operations.
22490 commit : function(){
22491 this.dirty = false;
22492 delete this.modified;
22493 this.editing = false;
22495 this.store.afterCommit(this);
22500 hasError : function(){
22501 return this.error != null;
22505 clearError : function(){
22510 * Creates a copy of this record.
22511 * @param {String} id (optional) A new record id if you don't want to use this record's id
22514 copy : function(newId) {
22515 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22519 * Ext JS Library 1.1.1
22520 * Copyright(c) 2006-2007, Ext JS, LLC.
22522 * Originally Released Under LGPL - original licence link has changed is not relivant.
22525 * <script type="text/javascript">
22531 * @class Roo.data.Store
22532 * @extends Roo.util.Observable
22533 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22534 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22536 * 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
22537 * has no knowledge of the format of the data returned by the Proxy.<br>
22539 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22540 * instances from the data object. These records are cached and made available through accessor functions.
22542 * Creates a new Store.
22543 * @param {Object} config A config object containing the objects needed for the Store to access data,
22544 * and read the data into Records.
22546 Roo.data.Store = function(config){
22547 this.data = new Roo.util.MixedCollection(false);
22548 this.data.getKey = function(o){
22551 this.baseParams = {};
22553 this.paramNames = {
22558 "multisort" : "_multisort"
22561 if(config && config.data){
22562 this.inlineData = config.data;
22563 delete config.data;
22566 Roo.apply(this, config);
22568 if(this.reader){ // reader passed
22569 this.reader = Roo.factory(this.reader, Roo.data);
22570 this.reader.xmodule = this.xmodule || false;
22571 if(!this.recordType){
22572 this.recordType = this.reader.recordType;
22574 if(this.reader.onMetaChange){
22575 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22579 if(this.recordType){
22580 this.fields = this.recordType.prototype.fields;
22582 this.modified = [];
22586 * @event datachanged
22587 * Fires when the data cache has changed, and a widget which is using this Store
22588 * as a Record cache should refresh its view.
22589 * @param {Store} this
22591 datachanged : true,
22593 * @event metachange
22594 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22595 * @param {Store} this
22596 * @param {Object} meta The JSON metadata
22601 * Fires when Records have been added to the Store
22602 * @param {Store} this
22603 * @param {Roo.data.Record[]} records The array of Records added
22604 * @param {Number} index The index at which the record(s) were added
22609 * Fires when a Record has been removed from the Store
22610 * @param {Store} this
22611 * @param {Roo.data.Record} record The Record that was removed
22612 * @param {Number} index The index at which the record was removed
22617 * Fires when a Record has been updated
22618 * @param {Store} this
22619 * @param {Roo.data.Record} record The Record that was updated
22620 * @param {String} operation The update operation being performed. Value may be one of:
22622 Roo.data.Record.EDIT
22623 Roo.data.Record.REJECT
22624 Roo.data.Record.COMMIT
22630 * Fires when the data cache has been cleared.
22631 * @param {Store} this
22635 * @event beforeload
22636 * Fires before a request is made for a new data object. If the beforeload handler returns false
22637 * the load action will be canceled.
22638 * @param {Store} this
22639 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22643 * @event beforeloadadd
22644 * Fires after a new set of Records has been loaded.
22645 * @param {Store} this
22646 * @param {Roo.data.Record[]} records The Records that were loaded
22647 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22649 beforeloadadd : true,
22652 * Fires after a new set of Records has been loaded, before they are added to the store.
22653 * @param {Store} this
22654 * @param {Roo.data.Record[]} records The Records that were loaded
22655 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22656 * @params {Object} return from reader
22660 * @event loadexception
22661 * Fires if an exception occurs in the Proxy during loading.
22662 * Called with the signature of the Proxy's "loadexception" event.
22663 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22666 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22667 * @param {Object} load options
22668 * @param {Object} jsonData from your request (normally this contains the Exception)
22670 loadexception : true
22674 this.proxy = Roo.factory(this.proxy, Roo.data);
22675 this.proxy.xmodule = this.xmodule || false;
22676 this.relayEvents(this.proxy, ["loadexception"]);
22678 this.sortToggle = {};
22679 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22681 Roo.data.Store.superclass.constructor.call(this);
22683 if(this.inlineData){
22684 this.loadData(this.inlineData);
22685 delete this.inlineData;
22689 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22691 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22692 * without a remote query - used by combo/forms at present.
22696 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22699 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22702 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22703 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22706 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22707 * on any HTTP request
22710 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22713 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22717 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22718 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22720 remoteSort : false,
22723 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22724 * loaded or when a record is removed. (defaults to false).
22726 pruneModifiedRecords : false,
22729 lastOptions : null,
22732 * Add Records to the Store and fires the add event.
22733 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22735 add : function(records){
22736 records = [].concat(records);
22737 for(var i = 0, len = records.length; i < len; i++){
22738 records[i].join(this);
22740 var index = this.data.length;
22741 this.data.addAll(records);
22742 this.fireEvent("add", this, records, index);
22746 * Remove a Record from the Store and fires the remove event.
22747 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22749 remove : function(record){
22750 var index = this.data.indexOf(record);
22751 this.data.removeAt(index);
22752 if(this.pruneModifiedRecords){
22753 this.modified.remove(record);
22755 this.fireEvent("remove", this, record, index);
22759 * Remove all Records from the Store and fires the clear event.
22761 removeAll : function(){
22763 if(this.pruneModifiedRecords){
22764 this.modified = [];
22766 this.fireEvent("clear", this);
22770 * Inserts Records to the Store at the given index and fires the add event.
22771 * @param {Number} index The start index at which to insert the passed Records.
22772 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22774 insert : function(index, records){
22775 records = [].concat(records);
22776 for(var i = 0, len = records.length; i < len; i++){
22777 this.data.insert(index, records[i]);
22778 records[i].join(this);
22780 this.fireEvent("add", this, records, index);
22784 * Get the index within the cache of the passed Record.
22785 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22786 * @return {Number} The index of the passed Record. Returns -1 if not found.
22788 indexOf : function(record){
22789 return this.data.indexOf(record);
22793 * Get the index within the cache of the Record with the passed id.
22794 * @param {String} id The id of the Record to find.
22795 * @return {Number} The index of the Record. Returns -1 if not found.
22797 indexOfId : function(id){
22798 return this.data.indexOfKey(id);
22802 * Get the Record with the specified id.
22803 * @param {String} id The id of the Record to find.
22804 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22806 getById : function(id){
22807 return this.data.key(id);
22811 * Get the Record at the specified index.
22812 * @param {Number} index The index of the Record to find.
22813 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22815 getAt : function(index){
22816 return this.data.itemAt(index);
22820 * Returns a range of Records between specified indices.
22821 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22822 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22823 * @return {Roo.data.Record[]} An array of Records
22825 getRange : function(start, end){
22826 return this.data.getRange(start, end);
22830 storeOptions : function(o){
22831 o = Roo.apply({}, o);
22834 this.lastOptions = o;
22838 * Loads the Record cache from the configured Proxy using the configured Reader.
22840 * If using remote paging, then the first load call must specify the <em>start</em>
22841 * and <em>limit</em> properties in the options.params property to establish the initial
22842 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22844 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22845 * and this call will return before the new data has been loaded. Perform any post-processing
22846 * in a callback function, or in a "load" event handler.</strong>
22848 * @param {Object} options An object containing properties which control loading options:<ul>
22849 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22850 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22851 * passed the following arguments:<ul>
22852 * <li>r : Roo.data.Record[]</li>
22853 * <li>options: Options object from the load call</li>
22854 * <li>success: Boolean success indicator</li></ul></li>
22855 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22856 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22859 load : function(options){
22860 options = options || {};
22861 if(this.fireEvent("beforeload", this, options) !== false){
22862 this.storeOptions(options);
22863 var p = Roo.apply(options.params || {}, this.baseParams);
22864 // if meta was not loaded from remote source.. try requesting it.
22865 if (!this.reader.metaFromRemote) {
22866 p._requestMeta = 1;
22868 if(this.sortInfo && this.remoteSort){
22869 var pn = this.paramNames;
22870 p[pn["sort"]] = this.sortInfo.field;
22871 p[pn["dir"]] = this.sortInfo.direction;
22873 if (this.multiSort) {
22874 var pn = this.paramNames;
22875 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
22878 this.proxy.load(p, this.reader, this.loadRecords, this, options);
22883 * Reloads the Record cache from the configured Proxy using the configured Reader and
22884 * the options from the last load operation performed.
22885 * @param {Object} options (optional) An object containing properties which may override the options
22886 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
22887 * the most recently used options are reused).
22889 reload : function(options){
22890 this.load(Roo.applyIf(options||{}, this.lastOptions));
22894 // Called as a callback by the Reader during a load operation.
22895 loadRecords : function(o, options, success){
22896 if(!o || success === false){
22897 if(success !== false){
22898 this.fireEvent("load", this, [], options, o);
22900 if(options.callback){
22901 options.callback.call(options.scope || this, [], options, false);
22905 // if data returned failure - throw an exception.
22906 if (o.success === false) {
22907 // show a message if no listener is registered.
22908 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
22909 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
22911 // loadmask wil be hooked into this..
22912 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
22915 var r = o.records, t = o.totalRecords || r.length;
22917 this.fireEvent("beforeloadadd", this, r, options, o);
22919 if(!options || options.add !== true){
22920 if(this.pruneModifiedRecords){
22921 this.modified = [];
22923 for(var i = 0, len = r.length; i < len; i++){
22927 this.data = this.snapshot;
22928 delete this.snapshot;
22931 this.data.addAll(r);
22932 this.totalLength = t;
22934 this.fireEvent("datachanged", this);
22936 this.totalLength = Math.max(t, this.data.length+r.length);
22939 this.fireEvent("load", this, r, options, o);
22940 if(options.callback){
22941 options.callback.call(options.scope || this, r, options, true);
22947 * Loads data from a passed data block. A Reader which understands the format of the data
22948 * must have been configured in the constructor.
22949 * @param {Object} data The data block from which to read the Records. The format of the data expected
22950 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
22951 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
22953 loadData : function(o, append){
22954 var r = this.reader.readRecords(o);
22955 this.loadRecords(r, {add: append}, true);
22959 * Gets the number of cached records.
22961 * <em>If using paging, this may not be the total size of the dataset. If the data object
22962 * used by the Reader contains the dataset size, then the getTotalCount() function returns
22963 * the data set size</em>
22965 getCount : function(){
22966 return this.data.length || 0;
22970 * Gets the total number of records in the dataset as returned by the server.
22972 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
22973 * the dataset size</em>
22975 getTotalCount : function(){
22976 return this.totalLength || 0;
22980 * Returns the sort state of the Store as an object with two properties:
22982 field {String} The name of the field by which the Records are sorted
22983 direction {String} The sort order, "ASC" or "DESC"
22986 getSortState : function(){
22987 return this.sortInfo;
22991 applySort : function(){
22992 if(this.sortInfo && !this.remoteSort){
22993 var s = this.sortInfo, f = s.field;
22994 var st = this.fields.get(f).sortType;
22995 var fn = function(r1, r2){
22996 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
22997 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
22999 this.data.sort(s.direction, fn);
23000 if(this.snapshot && this.snapshot != this.data){
23001 this.snapshot.sort(s.direction, fn);
23007 * Sets the default sort column and order to be used by the next load operation.
23008 * @param {String} fieldName The name of the field to sort by.
23009 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23011 setDefaultSort : function(field, dir){
23012 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23016 * Sort the Records.
23017 * If remote sorting is used, the sort is performed on the server, and the cache is
23018 * reloaded. If local sorting is used, the cache is sorted internally.
23019 * @param {String} fieldName The name of the field to sort by.
23020 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23022 sort : function(fieldName, dir){
23023 var f = this.fields.get(fieldName);
23025 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23027 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23028 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23033 this.sortToggle[f.name] = dir;
23034 this.sortInfo = {field: f.name, direction: dir};
23035 if(!this.remoteSort){
23037 this.fireEvent("datachanged", this);
23039 this.load(this.lastOptions);
23044 * Calls the specified function for each of the Records in the cache.
23045 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23046 * Returning <em>false</em> aborts and exits the iteration.
23047 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23049 each : function(fn, scope){
23050 this.data.each(fn, scope);
23054 * Gets all records modified since the last commit. Modified records are persisted across load operations
23055 * (e.g., during paging).
23056 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23058 getModifiedRecords : function(){
23059 return this.modified;
23063 createFilterFn : function(property, value, anyMatch){
23064 if(!value.exec){ // not a regex
23065 value = String(value);
23066 if(value.length == 0){
23069 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23071 return function(r){
23072 return value.test(r.data[property]);
23077 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23078 * @param {String} property A field on your records
23079 * @param {Number} start The record index to start at (defaults to 0)
23080 * @param {Number} end The last record index to include (defaults to length - 1)
23081 * @return {Number} The sum
23083 sum : function(property, start, end){
23084 var rs = this.data.items, v = 0;
23085 start = start || 0;
23086 end = (end || end === 0) ? end : rs.length-1;
23088 for(var i = start; i <= end; i++){
23089 v += (rs[i].data[property] || 0);
23095 * Filter the records by a specified property.
23096 * @param {String} field A field on your records
23097 * @param {String/RegExp} value Either a string that the field
23098 * should start with or a RegExp to test against the field
23099 * @param {Boolean} anyMatch True to match any part not just the beginning
23101 filter : function(property, value, anyMatch){
23102 var fn = this.createFilterFn(property, value, anyMatch);
23103 return fn ? this.filterBy(fn) : this.clearFilter();
23107 * Filter by a function. The specified function will be called with each
23108 * record in this data source. If the function returns true the record is included,
23109 * otherwise it is filtered.
23110 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23111 * @param {Object} scope (optional) The scope of the function (defaults to this)
23113 filterBy : function(fn, scope){
23114 this.snapshot = this.snapshot || this.data;
23115 this.data = this.queryBy(fn, scope||this);
23116 this.fireEvent("datachanged", this);
23120 * Query the records by a specified property.
23121 * @param {String} field A field on your records
23122 * @param {String/RegExp} value Either a string that the field
23123 * should start with or a RegExp to test against the field
23124 * @param {Boolean} anyMatch True to match any part not just the beginning
23125 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23127 query : function(property, value, anyMatch){
23128 var fn = this.createFilterFn(property, value, anyMatch);
23129 return fn ? this.queryBy(fn) : this.data.clone();
23133 * Query by a function. The specified function will be called with each
23134 * record in this data source. If the function returns true the record is included
23136 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23137 * @param {Object} scope (optional) The scope of the function (defaults to this)
23138 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23140 queryBy : function(fn, scope){
23141 var data = this.snapshot || this.data;
23142 return data.filterBy(fn, scope||this);
23146 * Collects unique values for a particular dataIndex from this store.
23147 * @param {String} dataIndex The property to collect
23148 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23149 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23150 * @return {Array} An array of the unique values
23152 collect : function(dataIndex, allowNull, bypassFilter){
23153 var d = (bypassFilter === true && this.snapshot) ?
23154 this.snapshot.items : this.data.items;
23155 var v, sv, r = [], l = {};
23156 for(var i = 0, len = d.length; i < len; i++){
23157 v = d[i].data[dataIndex];
23159 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23168 * Revert to a view of the Record cache with no filtering applied.
23169 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23171 clearFilter : function(suppressEvent){
23172 if(this.snapshot && this.snapshot != this.data){
23173 this.data = this.snapshot;
23174 delete this.snapshot;
23175 if(suppressEvent !== true){
23176 this.fireEvent("datachanged", this);
23182 afterEdit : function(record){
23183 if(this.modified.indexOf(record) == -1){
23184 this.modified.push(record);
23186 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23190 afterReject : function(record){
23191 this.modified.remove(record);
23192 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23196 afterCommit : function(record){
23197 this.modified.remove(record);
23198 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23202 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23203 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23205 commitChanges : function(){
23206 var m = this.modified.slice(0);
23207 this.modified = [];
23208 for(var i = 0, len = m.length; i < len; i++){
23214 * Cancel outstanding changes on all changed records.
23216 rejectChanges : function(){
23217 var m = this.modified.slice(0);
23218 this.modified = [];
23219 for(var i = 0, len = m.length; i < len; i++){
23224 onMetaChange : function(meta, rtype, o){
23225 this.recordType = rtype;
23226 this.fields = rtype.prototype.fields;
23227 delete this.snapshot;
23228 this.sortInfo = meta.sortInfo || this.sortInfo;
23229 this.modified = [];
23230 this.fireEvent('metachange', this, this.reader.meta);
23233 moveIndex : function(data, type)
23235 var index = this.indexOf(data);
23237 var newIndex = index + type;
23241 this.insert(newIndex, data);
23246 * Ext JS Library 1.1.1
23247 * Copyright(c) 2006-2007, Ext JS, LLC.
23249 * Originally Released Under LGPL - original licence link has changed is not relivant.
23252 * <script type="text/javascript">
23256 * @class Roo.data.SimpleStore
23257 * @extends Roo.data.Store
23258 * Small helper class to make creating Stores from Array data easier.
23259 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23260 * @cfg {Array} fields An array of field definition objects, or field name strings.
23261 * @cfg {Array} data The multi-dimensional array of data
23263 * @param {Object} config
23265 Roo.data.SimpleStore = function(config){
23266 Roo.data.SimpleStore.superclass.constructor.call(this, {
23268 reader: new Roo.data.ArrayReader({
23271 Roo.data.Record.create(config.fields)
23273 proxy : new Roo.data.MemoryProxy(config.data)
23277 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23279 * Ext JS Library 1.1.1
23280 * Copyright(c) 2006-2007, Ext JS, LLC.
23282 * Originally Released Under LGPL - original licence link has changed is not relivant.
23285 * <script type="text/javascript">
23290 * @extends Roo.data.Store
23291 * @class Roo.data.JsonStore
23292 * Small helper class to make creating Stores for JSON data easier. <br/>
23294 var store = new Roo.data.JsonStore({
23295 url: 'get-images.php',
23297 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23300 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23301 * JsonReader and HttpProxy (unless inline data is provided).</b>
23302 * @cfg {Array} fields An array of field definition objects, or field name strings.
23304 * @param {Object} config
23306 Roo.data.JsonStore = function(c){
23307 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23308 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23309 reader: new Roo.data.JsonReader(c, c.fields)
23312 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23314 * Ext JS Library 1.1.1
23315 * Copyright(c) 2006-2007, Ext JS, LLC.
23317 * Originally Released Under LGPL - original licence link has changed is not relivant.
23320 * <script type="text/javascript">
23324 Roo.data.Field = function(config){
23325 if(typeof config == "string"){
23326 config = {name: config};
23328 Roo.apply(this, config);
23331 this.type = "auto";
23334 var st = Roo.data.SortTypes;
23335 // named sortTypes are supported, here we look them up
23336 if(typeof this.sortType == "string"){
23337 this.sortType = st[this.sortType];
23340 // set default sortType for strings and dates
23341 if(!this.sortType){
23344 this.sortType = st.asUCString;
23347 this.sortType = st.asDate;
23350 this.sortType = st.none;
23355 var stripRe = /[\$,%]/g;
23357 // prebuilt conversion function for this field, instead of
23358 // switching every time we're reading a value
23360 var cv, dateFormat = this.dateFormat;
23365 cv = function(v){ return v; };
23368 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23372 return v !== undefined && v !== null && v !== '' ?
23373 parseInt(String(v).replace(stripRe, ""), 10) : '';
23378 return v !== undefined && v !== null && v !== '' ?
23379 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23384 cv = function(v){ return v === true || v === "true" || v == 1; };
23391 if(v instanceof Date){
23395 if(dateFormat == "timestamp"){
23396 return new Date(v*1000);
23398 return Date.parseDate(v, dateFormat);
23400 var parsed = Date.parse(v);
23401 return parsed ? new Date(parsed) : null;
23410 Roo.data.Field.prototype = {
23418 * Ext JS Library 1.1.1
23419 * Copyright(c) 2006-2007, Ext JS, LLC.
23421 * Originally Released Under LGPL - original licence link has changed is not relivant.
23424 * <script type="text/javascript">
23427 // Base class for reading structured data from a data source. This class is intended to be
23428 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23431 * @class Roo.data.DataReader
23432 * Base class for reading structured data from a data source. This class is intended to be
23433 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23436 Roo.data.DataReader = function(meta, recordType){
23440 this.recordType = recordType instanceof Array ?
23441 Roo.data.Record.create(recordType) : recordType;
23444 Roo.data.DataReader.prototype = {
23446 * Create an empty record
23447 * @param {Object} data (optional) - overlay some values
23448 * @return {Roo.data.Record} record created.
23450 newRow : function(d) {
23452 this.recordType.prototype.fields.each(function(c) {
23454 case 'int' : da[c.name] = 0; break;
23455 case 'date' : da[c.name] = new Date(); break;
23456 case 'float' : da[c.name] = 0.0; break;
23457 case 'boolean' : da[c.name] = false; break;
23458 default : da[c.name] = ""; break;
23462 return new this.recordType(Roo.apply(da, d));
23467 * Ext JS Library 1.1.1
23468 * Copyright(c) 2006-2007, Ext JS, LLC.
23470 * Originally Released Under LGPL - original licence link has changed is not relivant.
23473 * <script type="text/javascript">
23477 * @class Roo.data.DataProxy
23478 * @extends Roo.data.Observable
23479 * This class is an abstract base class for implementations which provide retrieval of
23480 * unformatted data objects.<br>
23482 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23483 * (of the appropriate type which knows how to parse the data object) to provide a block of
23484 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23486 * Custom implementations must implement the load method as described in
23487 * {@link Roo.data.HttpProxy#load}.
23489 Roo.data.DataProxy = function(){
23492 * @event beforeload
23493 * Fires before a network request is made to retrieve a data object.
23494 * @param {Object} This DataProxy object.
23495 * @param {Object} params The params parameter to the load function.
23500 * Fires before the load method's callback is called.
23501 * @param {Object} This DataProxy object.
23502 * @param {Object} o The data object.
23503 * @param {Object} arg The callback argument object passed to the load function.
23507 * @event loadexception
23508 * Fires if an Exception occurs during data retrieval.
23509 * @param {Object} This DataProxy object.
23510 * @param {Object} o The data object.
23511 * @param {Object} arg The callback argument object passed to the load function.
23512 * @param {Object} e The Exception.
23514 loadexception : true
23516 Roo.data.DataProxy.superclass.constructor.call(this);
23519 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23522 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23526 * Ext JS Library 1.1.1
23527 * Copyright(c) 2006-2007, Ext JS, LLC.
23529 * Originally Released Under LGPL - original licence link has changed is not relivant.
23532 * <script type="text/javascript">
23535 * @class Roo.data.MemoryProxy
23536 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23537 * to the Reader when its load method is called.
23539 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23541 Roo.data.MemoryProxy = function(data){
23545 Roo.data.MemoryProxy.superclass.constructor.call(this);
23549 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23551 * Load data from the requested source (in this case an in-memory
23552 * data object passed to the constructor), read the data object into
23553 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23554 * process that block using the passed callback.
23555 * @param {Object} params This parameter is not used by the MemoryProxy class.
23556 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23557 * object into a block of Roo.data.Records.
23558 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23559 * The function must be passed <ul>
23560 * <li>The Record block object</li>
23561 * <li>The "arg" argument from the load function</li>
23562 * <li>A boolean success indicator</li>
23564 * @param {Object} scope The scope in which to call the callback
23565 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23567 load : function(params, reader, callback, scope, arg){
23568 params = params || {};
23571 result = reader.readRecords(this.data);
23573 this.fireEvent("loadexception", this, arg, null, e);
23574 callback.call(scope, null, arg, false);
23577 callback.call(scope, result, arg, true);
23581 update : function(params, records){
23586 * Ext JS Library 1.1.1
23587 * Copyright(c) 2006-2007, Ext JS, LLC.
23589 * Originally Released Under LGPL - original licence link has changed is not relivant.
23592 * <script type="text/javascript">
23595 * @class Roo.data.HttpProxy
23596 * @extends Roo.data.DataProxy
23597 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23598 * configured to reference a certain URL.<br><br>
23600 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23601 * from which the running page was served.<br><br>
23603 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23605 * Be aware that to enable the browser to parse an XML document, the server must set
23606 * the Content-Type header in the HTTP response to "text/xml".
23608 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23609 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23610 * will be used to make the request.
23612 Roo.data.HttpProxy = function(conn){
23613 Roo.data.HttpProxy.superclass.constructor.call(this);
23614 // is conn a conn config or a real conn?
23616 this.useAjax = !conn || !conn.events;
23620 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23621 // thse are take from connection...
23624 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23627 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23628 * extra parameters to each request made by this object. (defaults to undefined)
23631 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23632 * to each request made by this object. (defaults to undefined)
23635 * @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)
23638 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23641 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23647 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23651 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23652 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23653 * a finer-grained basis than the DataProxy events.
23655 getConnection : function(){
23656 return this.useAjax ? Roo.Ajax : this.conn;
23660 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23661 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23662 * process that block using the passed callback.
23663 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23664 * for the request to the remote server.
23665 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23666 * object into a block of Roo.data.Records.
23667 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23668 * The function must be passed <ul>
23669 * <li>The Record block object</li>
23670 * <li>The "arg" argument from the load function</li>
23671 * <li>A boolean success indicator</li>
23673 * @param {Object} scope The scope in which to call the callback
23674 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23676 load : function(params, reader, callback, scope, arg){
23677 if(this.fireEvent("beforeload", this, params) !== false){
23679 params : params || {},
23681 callback : callback,
23686 callback : this.loadResponse,
23690 Roo.applyIf(o, this.conn);
23691 if(this.activeRequest){
23692 Roo.Ajax.abort(this.activeRequest);
23694 this.activeRequest = Roo.Ajax.request(o);
23696 this.conn.request(o);
23699 callback.call(scope||this, null, arg, false);
23704 loadResponse : function(o, success, response){
23705 delete this.activeRequest;
23707 this.fireEvent("loadexception", this, o, response);
23708 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23713 result = o.reader.read(response);
23715 this.fireEvent("loadexception", this, o, response, e);
23716 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23720 this.fireEvent("load", this, o, o.request.arg);
23721 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23725 update : function(dataSet){
23730 updateResponse : function(dataSet){
23735 * Ext JS Library 1.1.1
23736 * Copyright(c) 2006-2007, Ext JS, LLC.
23738 * Originally Released Under LGPL - original licence link has changed is not relivant.
23741 * <script type="text/javascript">
23745 * @class Roo.data.ScriptTagProxy
23746 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23747 * other than the originating domain of the running page.<br><br>
23749 * <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
23750 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23752 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23753 * source code that is used as the source inside a <script> tag.<br><br>
23755 * In order for the browser to process the returned data, the server must wrap the data object
23756 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23757 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23758 * depending on whether the callback name was passed:
23761 boolean scriptTag = false;
23762 String cb = request.getParameter("callback");
23765 response.setContentType("text/javascript");
23767 response.setContentType("application/x-json");
23769 Writer out = response.getWriter();
23771 out.write(cb + "(");
23773 out.print(dataBlock.toJsonString());
23780 * @param {Object} config A configuration object.
23782 Roo.data.ScriptTagProxy = function(config){
23783 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23784 Roo.apply(this, config);
23785 this.head = document.getElementsByTagName("head")[0];
23788 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23790 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23792 * @cfg {String} url The URL from which to request the data object.
23795 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23799 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23800 * the server the name of the callback function set up by the load call to process the returned data object.
23801 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23802 * javascript output which calls this named function passing the data object as its only parameter.
23804 callbackParam : "callback",
23806 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23807 * name to the request.
23812 * Load data from the configured URL, read the data object into
23813 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23814 * process that block using the passed callback.
23815 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23816 * for the request to the remote server.
23817 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23818 * object into a block of Roo.data.Records.
23819 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23820 * The function must be passed <ul>
23821 * <li>The Record block object</li>
23822 * <li>The "arg" argument from the load function</li>
23823 * <li>A boolean success indicator</li>
23825 * @param {Object} scope The scope in which to call the callback
23826 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23828 load : function(params, reader, callback, scope, arg){
23829 if(this.fireEvent("beforeload", this, params) !== false){
23831 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23833 var url = this.url;
23834 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23836 url += "&_dc=" + (new Date().getTime());
23838 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23841 cb : "stcCallback"+transId,
23842 scriptId : "stcScript"+transId,
23846 callback : callback,
23852 window[trans.cb] = function(o){
23853 conn.handleResponse(o, trans);
23856 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23858 if(this.autoAbort !== false){
23862 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
23864 var script = document.createElement("script");
23865 script.setAttribute("src", url);
23866 script.setAttribute("type", "text/javascript");
23867 script.setAttribute("id", trans.scriptId);
23868 this.head.appendChild(script);
23870 this.trans = trans;
23872 callback.call(scope||this, null, arg, false);
23877 isLoading : function(){
23878 return this.trans ? true : false;
23882 * Abort the current server request.
23884 abort : function(){
23885 if(this.isLoading()){
23886 this.destroyTrans(this.trans);
23891 destroyTrans : function(trans, isLoaded){
23892 this.head.removeChild(document.getElementById(trans.scriptId));
23893 clearTimeout(trans.timeoutId);
23895 window[trans.cb] = undefined;
23897 delete window[trans.cb];
23900 // if hasn't been loaded, wait for load to remove it to prevent script error
23901 window[trans.cb] = function(){
23902 window[trans.cb] = undefined;
23904 delete window[trans.cb];
23911 handleResponse : function(o, trans){
23912 this.trans = false;
23913 this.destroyTrans(trans, true);
23916 result = trans.reader.readRecords(o);
23918 this.fireEvent("loadexception", this, o, trans.arg, e);
23919 trans.callback.call(trans.scope||window, null, trans.arg, false);
23922 this.fireEvent("load", this, o, trans.arg);
23923 trans.callback.call(trans.scope||window, result, trans.arg, true);
23927 handleFailure : function(trans){
23928 this.trans = false;
23929 this.destroyTrans(trans, false);
23930 this.fireEvent("loadexception", this, null, trans.arg);
23931 trans.callback.call(trans.scope||window, null, trans.arg, false);
23935 * Ext JS Library 1.1.1
23936 * Copyright(c) 2006-2007, Ext JS, LLC.
23938 * Originally Released Under LGPL - original licence link has changed is not relivant.
23941 * <script type="text/javascript">
23945 * @class Roo.data.JsonReader
23946 * @extends Roo.data.DataReader
23947 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
23948 * based on mappings in a provided Roo.data.Record constructor.
23950 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
23951 * in the reply previously.
23956 var RecordDef = Roo.data.Record.create([
23957 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
23958 {name: 'occupation'} // This field will use "occupation" as the mapping.
23960 var myReader = new Roo.data.JsonReader({
23961 totalProperty: "results", // The property which contains the total dataset size (optional)
23962 root: "rows", // The property which contains an Array of row objects
23963 id: "id" // The property within each row object that provides an ID for the record (optional)
23967 * This would consume a JSON file like this:
23969 { 'results': 2, 'rows': [
23970 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
23971 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
23974 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
23975 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
23976 * paged from the remote server.
23977 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
23978 * @cfg {String} root name of the property which contains the Array of row objects.
23979 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
23980 * @cfg {Array} fields Array of field definition objects
23982 * Create a new JsonReader
23983 * @param {Object} meta Metadata configuration options
23984 * @param {Object} recordType Either an Array of field definition objects,
23985 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
23987 Roo.data.JsonReader = function(meta, recordType){
23990 // set some defaults:
23991 Roo.applyIf(meta, {
23992 totalProperty: 'total',
23993 successProperty : 'success',
23998 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24000 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24003 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24004 * Used by Store query builder to append _requestMeta to params.
24007 metaFromRemote : false,
24009 * This method is only used by a DataProxy which has retrieved data from a remote server.
24010 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24011 * @return {Object} data A data block which is used by an Roo.data.Store object as
24012 * a cache of Roo.data.Records.
24014 read : function(response){
24015 var json = response.responseText;
24017 var o = /* eval:var:o */ eval("("+json+")");
24019 throw {message: "JsonReader.read: Json object not found"};
24025 this.metaFromRemote = true;
24026 this.meta = o.metaData;
24027 this.recordType = Roo.data.Record.create(o.metaData.fields);
24028 this.onMetaChange(this.meta, this.recordType, o);
24030 return this.readRecords(o);
24033 // private function a store will implement
24034 onMetaChange : function(meta, recordType, o){
24041 simpleAccess: function(obj, subsc) {
24048 getJsonAccessor: function(){
24050 return function(expr) {
24052 return(re.test(expr))
24053 ? new Function("obj", "return obj." + expr)
24058 return Roo.emptyFn;
24063 * Create a data block containing Roo.data.Records from an XML document.
24064 * @param {Object} o An object which contains an Array of row objects in the property specified
24065 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24066 * which contains the total size of the dataset.
24067 * @return {Object} data A data block which is used by an Roo.data.Store object as
24068 * a cache of Roo.data.Records.
24070 readRecords : function(o){
24072 * After any data loads, the raw JSON data is available for further custom processing.
24076 var s = this.meta, Record = this.recordType,
24077 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24079 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24081 if(s.totalProperty) {
24082 this.getTotal = this.getJsonAccessor(s.totalProperty);
24084 if(s.successProperty) {
24085 this.getSuccess = this.getJsonAccessor(s.successProperty);
24087 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24089 var g = this.getJsonAccessor(s.id);
24090 this.getId = function(rec) {
24092 return (r === undefined || r === "") ? null : r;
24095 this.getId = function(){return null;};
24098 for(var jj = 0; jj < fl; jj++){
24100 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24101 this.ef[jj] = this.getJsonAccessor(map);
24105 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24106 if(s.totalProperty){
24107 var vt = parseInt(this.getTotal(o), 10);
24112 if(s.successProperty){
24113 var vs = this.getSuccess(o);
24114 if(vs === false || vs === 'false'){
24119 for(var i = 0; i < c; i++){
24122 var id = this.getId(n);
24123 for(var j = 0; j < fl; j++){
24125 var v = this.ef[j](n);
24127 Roo.log('missing convert for ' + f.name);
24131 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24133 var record = new Record(values, id);
24135 records[i] = record;
24141 totalRecords : totalRecords
24146 * Ext JS Library 1.1.1
24147 * Copyright(c) 2006-2007, Ext JS, LLC.
24149 * Originally Released Under LGPL - original licence link has changed is not relivant.
24152 * <script type="text/javascript">
24156 * @class Roo.data.XmlReader
24157 * @extends Roo.data.DataReader
24158 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24159 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24161 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24162 * header in the HTTP response must be set to "text/xml".</em>
24166 var RecordDef = Roo.data.Record.create([
24167 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24168 {name: 'occupation'} // This field will use "occupation" as the mapping.
24170 var myReader = new Roo.data.XmlReader({
24171 totalRecords: "results", // The element which contains the total dataset size (optional)
24172 record: "row", // The repeated element which contains row information
24173 id: "id" // The element within the row that provides an ID for the record (optional)
24177 * This would consume an XML file like this:
24181 <results>2</results>
24184 <name>Bill</name>
24185 <occupation>Gardener</occupation>
24189 <name>Ben</name>
24190 <occupation>Horticulturalist</occupation>
24194 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24195 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24196 * paged from the remote server.
24197 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24198 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24199 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24200 * a record identifier value.
24202 * Create a new XmlReader
24203 * @param {Object} meta Metadata configuration options
24204 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24205 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24206 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24208 Roo.data.XmlReader = function(meta, recordType){
24210 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24212 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24214 * This method is only used by a DataProxy which has retrieved data from a remote server.
24215 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24216 * to contain a method called 'responseXML' that returns an XML document object.
24217 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24218 * a cache of Roo.data.Records.
24220 read : function(response){
24221 var doc = response.responseXML;
24223 throw {message: "XmlReader.read: XML Document not available"};
24225 return this.readRecords(doc);
24229 * Create a data block containing Roo.data.Records from an XML document.
24230 * @param {Object} doc A parsed XML document.
24231 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24232 * a cache of Roo.data.Records.
24234 readRecords : function(doc){
24236 * After any data loads/reads, the raw XML Document is available for further custom processing.
24237 * @type XMLDocument
24239 this.xmlData = doc;
24240 var root = doc.documentElement || doc;
24241 var q = Roo.DomQuery;
24242 var recordType = this.recordType, fields = recordType.prototype.fields;
24243 var sid = this.meta.id;
24244 var totalRecords = 0, success = true;
24245 if(this.meta.totalRecords){
24246 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24249 if(this.meta.success){
24250 var sv = q.selectValue(this.meta.success, root, true);
24251 success = sv !== false && sv !== 'false';
24254 var ns = q.select(this.meta.record, root);
24255 for(var i = 0, len = ns.length; i < len; i++) {
24258 var id = sid ? q.selectValue(sid, n) : undefined;
24259 for(var j = 0, jlen = fields.length; j < jlen; j++){
24260 var f = fields.items[j];
24261 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24263 values[f.name] = v;
24265 var record = new recordType(values, id);
24267 records[records.length] = record;
24273 totalRecords : totalRecords || records.length
24278 * Ext JS Library 1.1.1
24279 * Copyright(c) 2006-2007, Ext JS, LLC.
24281 * Originally Released Under LGPL - original licence link has changed is not relivant.
24284 * <script type="text/javascript">
24288 * @class Roo.data.ArrayReader
24289 * @extends Roo.data.DataReader
24290 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24291 * Each element of that Array represents a row of data fields. The
24292 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24293 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24297 var RecordDef = Roo.data.Record.create([
24298 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24299 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24301 var myReader = new Roo.data.ArrayReader({
24302 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24306 * This would consume an Array like this:
24308 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24310 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24312 * Create a new JsonReader
24313 * @param {Object} meta Metadata configuration options.
24314 * @param {Object} recordType Either an Array of field definition objects
24315 * as specified to {@link Roo.data.Record#create},
24316 * or an {@link Roo.data.Record} object
24317 * created using {@link Roo.data.Record#create}.
24319 Roo.data.ArrayReader = function(meta, recordType){
24320 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24323 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24325 * Create a data block containing Roo.data.Records from an XML document.
24326 * @param {Object} o An Array of row objects which represents the dataset.
24327 * @return {Object} data A data block which is used by an Roo.data.Store object as
24328 * a cache of Roo.data.Records.
24330 readRecords : function(o){
24331 var sid = this.meta ? this.meta.id : null;
24332 var recordType = this.recordType, fields = recordType.prototype.fields;
24335 for(var i = 0; i < root.length; i++){
24338 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24339 for(var j = 0, jlen = fields.length; j < jlen; j++){
24340 var f = fields.items[j];
24341 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24342 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24344 values[f.name] = v;
24346 var record = new recordType(values, id);
24348 records[records.length] = record;
24352 totalRecords : records.length
24357 * Ext JS Library 1.1.1
24358 * Copyright(c) 2006-2007, Ext JS, LLC.
24360 * Originally Released Under LGPL - original licence link has changed is not relivant.
24363 * <script type="text/javascript">
24368 * @class Roo.data.Tree
24369 * @extends Roo.util.Observable
24370 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24371 * in the tree have most standard DOM functionality.
24373 * @param {Node} root (optional) The root node
24375 Roo.data.Tree = function(root){
24376 this.nodeHash = {};
24378 * The root node for this tree
24383 this.setRootNode(root);
24388 * Fires when a new child node is appended to a node in this tree.
24389 * @param {Tree} tree The owner tree
24390 * @param {Node} parent The parent node
24391 * @param {Node} node The newly appended node
24392 * @param {Number} index The index of the newly appended node
24397 * Fires when a child node is removed from a node in this tree.
24398 * @param {Tree} tree The owner tree
24399 * @param {Node} parent The parent node
24400 * @param {Node} node The child node removed
24405 * Fires when a node is moved to a new location in the tree
24406 * @param {Tree} tree The owner tree
24407 * @param {Node} node The node moved
24408 * @param {Node} oldParent The old parent of this node
24409 * @param {Node} newParent The new parent of this node
24410 * @param {Number} index The index it was moved to
24415 * Fires when a new child node is inserted in a node in this tree.
24416 * @param {Tree} tree The owner tree
24417 * @param {Node} parent The parent node
24418 * @param {Node} node The child node inserted
24419 * @param {Node} refNode The child node the node was inserted before
24423 * @event beforeappend
24424 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24425 * @param {Tree} tree The owner tree
24426 * @param {Node} parent The parent node
24427 * @param {Node} node The child node to be appended
24429 "beforeappend" : true,
24431 * @event beforeremove
24432 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24433 * @param {Tree} tree The owner tree
24434 * @param {Node} parent The parent node
24435 * @param {Node} node The child node to be removed
24437 "beforeremove" : true,
24439 * @event beforemove
24440 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24441 * @param {Tree} tree The owner tree
24442 * @param {Node} node The node being moved
24443 * @param {Node} oldParent The parent of the node
24444 * @param {Node} newParent The new parent the node is moving to
24445 * @param {Number} index The index it is being moved to
24447 "beforemove" : true,
24449 * @event beforeinsert
24450 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24451 * @param {Tree} tree The owner tree
24452 * @param {Node} parent The parent node
24453 * @param {Node} node The child node to be inserted
24454 * @param {Node} refNode The child node the node is being inserted before
24456 "beforeinsert" : true
24459 Roo.data.Tree.superclass.constructor.call(this);
24462 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24463 pathSeparator: "/",
24465 proxyNodeEvent : function(){
24466 return this.fireEvent.apply(this, arguments);
24470 * Returns the root node for this tree.
24473 getRootNode : function(){
24478 * Sets the root node for this tree.
24479 * @param {Node} node
24482 setRootNode : function(node){
24484 node.ownerTree = this;
24485 node.isRoot = true;
24486 this.registerNode(node);
24491 * Gets a node in this tree by its id.
24492 * @param {String} id
24495 getNodeById : function(id){
24496 return this.nodeHash[id];
24499 registerNode : function(node){
24500 this.nodeHash[node.id] = node;
24503 unregisterNode : function(node){
24504 delete this.nodeHash[node.id];
24507 toString : function(){
24508 return "[Tree"+(this.id?" "+this.id:"")+"]";
24513 * @class Roo.data.Node
24514 * @extends Roo.util.Observable
24515 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24516 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24518 * @param {Object} attributes The attributes/config for the node
24520 Roo.data.Node = function(attributes){
24522 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24525 this.attributes = attributes || {};
24526 this.leaf = this.attributes.leaf;
24528 * The node id. @type String
24530 this.id = this.attributes.id;
24532 this.id = Roo.id(null, "ynode-");
24533 this.attributes.id = this.id;
24538 * All child nodes of this node. @type Array
24540 this.childNodes = [];
24541 if(!this.childNodes.indexOf){ // indexOf is a must
24542 this.childNodes.indexOf = function(o){
24543 for(var i = 0, len = this.length; i < len; i++){
24552 * The parent node for this node. @type Node
24554 this.parentNode = null;
24556 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24558 this.firstChild = null;
24560 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24562 this.lastChild = null;
24564 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24566 this.previousSibling = null;
24568 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24570 this.nextSibling = null;
24575 * Fires when a new child node is appended
24576 * @param {Tree} tree The owner tree
24577 * @param {Node} this This node
24578 * @param {Node} node The newly appended node
24579 * @param {Number} index The index of the newly appended node
24584 * Fires when a child node is removed
24585 * @param {Tree} tree The owner tree
24586 * @param {Node} this This node
24587 * @param {Node} node The removed node
24592 * Fires when this node is moved to a new location in the tree
24593 * @param {Tree} tree The owner tree
24594 * @param {Node} this This node
24595 * @param {Node} oldParent The old parent of this node
24596 * @param {Node} newParent The new parent of this node
24597 * @param {Number} index The index it was moved to
24602 * Fires when a new child node is inserted.
24603 * @param {Tree} tree The owner tree
24604 * @param {Node} this This node
24605 * @param {Node} node The child node inserted
24606 * @param {Node} refNode The child node the node was inserted before
24610 * @event beforeappend
24611 * Fires before a new child is appended, return false to cancel the append.
24612 * @param {Tree} tree The owner tree
24613 * @param {Node} this This node
24614 * @param {Node} node The child node to be appended
24616 "beforeappend" : true,
24618 * @event beforeremove
24619 * Fires before a child is removed, return false to cancel the remove.
24620 * @param {Tree} tree The owner tree
24621 * @param {Node} this This node
24622 * @param {Node} node The child node to be removed
24624 "beforeremove" : true,
24626 * @event beforemove
24627 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24628 * @param {Tree} tree The owner tree
24629 * @param {Node} this This node
24630 * @param {Node} oldParent The parent of this node
24631 * @param {Node} newParent The new parent this node is moving to
24632 * @param {Number} index The index it is being moved to
24634 "beforemove" : true,
24636 * @event beforeinsert
24637 * Fires before a new child is inserted, return false to cancel the insert.
24638 * @param {Tree} tree The owner tree
24639 * @param {Node} this This node
24640 * @param {Node} node The child node to be inserted
24641 * @param {Node} refNode The child node the node is being inserted before
24643 "beforeinsert" : true
24645 this.listeners = this.attributes.listeners;
24646 Roo.data.Node.superclass.constructor.call(this);
24649 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24650 fireEvent : function(evtName){
24651 // first do standard event for this node
24652 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24655 // then bubble it up to the tree if the event wasn't cancelled
24656 var ot = this.getOwnerTree();
24658 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24666 * Returns true if this node is a leaf
24667 * @return {Boolean}
24669 isLeaf : function(){
24670 return this.leaf === true;
24674 setFirstChild : function(node){
24675 this.firstChild = node;
24679 setLastChild : function(node){
24680 this.lastChild = node;
24685 * Returns true if this node is the last child of its parent
24686 * @return {Boolean}
24688 isLast : function(){
24689 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24693 * Returns true if this node is the first child of its parent
24694 * @return {Boolean}
24696 isFirst : function(){
24697 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24700 hasChildNodes : function(){
24701 return !this.isLeaf() && this.childNodes.length > 0;
24705 * Insert node(s) as the last child node of this node.
24706 * @param {Node/Array} node The node or Array of nodes to append
24707 * @return {Node} The appended node if single append, or null if an array was passed
24709 appendChild : function(node){
24711 if(node instanceof Array){
24713 }else if(arguments.length > 1){
24716 // if passed an array or multiple args do them one by one
24718 for(var i = 0, len = multi.length; i < len; i++) {
24719 this.appendChild(multi[i]);
24722 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24725 var index = this.childNodes.length;
24726 var oldParent = node.parentNode;
24727 // it's a move, make sure we move it cleanly
24729 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24732 oldParent.removeChild(node);
24734 index = this.childNodes.length;
24736 this.setFirstChild(node);
24738 this.childNodes.push(node);
24739 node.parentNode = this;
24740 var ps = this.childNodes[index-1];
24742 node.previousSibling = ps;
24743 ps.nextSibling = node;
24745 node.previousSibling = null;
24747 node.nextSibling = null;
24748 this.setLastChild(node);
24749 node.setOwnerTree(this.getOwnerTree());
24750 this.fireEvent("append", this.ownerTree, this, node, index);
24752 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24759 * Removes a child node from this node.
24760 * @param {Node} node The node to remove
24761 * @return {Node} The removed node
24763 removeChild : function(node){
24764 var index = this.childNodes.indexOf(node);
24768 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24772 // remove it from childNodes collection
24773 this.childNodes.splice(index, 1);
24776 if(node.previousSibling){
24777 node.previousSibling.nextSibling = node.nextSibling;
24779 if(node.nextSibling){
24780 node.nextSibling.previousSibling = node.previousSibling;
24783 // update child refs
24784 if(this.firstChild == node){
24785 this.setFirstChild(node.nextSibling);
24787 if(this.lastChild == node){
24788 this.setLastChild(node.previousSibling);
24791 node.setOwnerTree(null);
24792 // clear any references from the node
24793 node.parentNode = null;
24794 node.previousSibling = null;
24795 node.nextSibling = null;
24796 this.fireEvent("remove", this.ownerTree, this, node);
24801 * Inserts the first node before the second node in this nodes childNodes collection.
24802 * @param {Node} node The node to insert
24803 * @param {Node} refNode The node to insert before (if null the node is appended)
24804 * @return {Node} The inserted node
24806 insertBefore : function(node, refNode){
24807 if(!refNode){ // like standard Dom, refNode can be null for append
24808 return this.appendChild(node);
24811 if(node == refNode){
24815 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24818 var index = this.childNodes.indexOf(refNode);
24819 var oldParent = node.parentNode;
24820 var refIndex = index;
24822 // when moving internally, indexes will change after remove
24823 if(oldParent == this && this.childNodes.indexOf(node) < index){
24827 // it's a move, make sure we move it cleanly
24829 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24832 oldParent.removeChild(node);
24835 this.setFirstChild(node);
24837 this.childNodes.splice(refIndex, 0, node);
24838 node.parentNode = this;
24839 var ps = this.childNodes[refIndex-1];
24841 node.previousSibling = ps;
24842 ps.nextSibling = node;
24844 node.previousSibling = null;
24846 node.nextSibling = refNode;
24847 refNode.previousSibling = node;
24848 node.setOwnerTree(this.getOwnerTree());
24849 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24851 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24857 * Returns the child node at the specified index.
24858 * @param {Number} index
24861 item : function(index){
24862 return this.childNodes[index];
24866 * Replaces one child node in this node with another.
24867 * @param {Node} newChild The replacement node
24868 * @param {Node} oldChild The node to replace
24869 * @return {Node} The replaced node
24871 replaceChild : function(newChild, oldChild){
24872 this.insertBefore(newChild, oldChild);
24873 this.removeChild(oldChild);
24878 * Returns the index of a child node
24879 * @param {Node} node
24880 * @return {Number} The index of the node or -1 if it was not found
24882 indexOf : function(child){
24883 return this.childNodes.indexOf(child);
24887 * Returns the tree this node is in.
24890 getOwnerTree : function(){
24891 // if it doesn't have one, look for one
24892 if(!this.ownerTree){
24896 this.ownerTree = p.ownerTree;
24902 return this.ownerTree;
24906 * Returns depth of this node (the root node has a depth of 0)
24909 getDepth : function(){
24912 while(p.parentNode){
24920 setOwnerTree : function(tree){
24921 // if it's move, we need to update everyone
24922 if(tree != this.ownerTree){
24923 if(this.ownerTree){
24924 this.ownerTree.unregisterNode(this);
24926 this.ownerTree = tree;
24927 var cs = this.childNodes;
24928 for(var i = 0, len = cs.length; i < len; i++) {
24929 cs[i].setOwnerTree(tree);
24932 tree.registerNode(this);
24938 * Returns the path for this node. The path can be used to expand or select this node programmatically.
24939 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
24940 * @return {String} The path
24942 getPath : function(attr){
24943 attr = attr || "id";
24944 var p = this.parentNode;
24945 var b = [this.attributes[attr]];
24947 b.unshift(p.attributes[attr]);
24950 var sep = this.getOwnerTree().pathSeparator;
24951 return sep + b.join(sep);
24955 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
24956 * function call will be the scope provided or the current node. The arguments to the function
24957 * will be the args provided or the current node. If the function returns false at any point,
24958 * the bubble is stopped.
24959 * @param {Function} fn The function to call
24960 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24961 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
24963 bubble : function(fn, scope, args){
24966 if(fn.call(scope || p, args || p) === false){
24974 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
24975 * function call will be the scope provided or the current node. The arguments to the function
24976 * will be the args provided or the current node. If the function returns false at any point,
24977 * the cascade is stopped on that branch.
24978 * @param {Function} fn The function to call
24979 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24980 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
24982 cascade : function(fn, scope, args){
24983 if(fn.call(scope || this, args || this) !== false){
24984 var cs = this.childNodes;
24985 for(var i = 0, len = cs.length; i < len; i++) {
24986 cs[i].cascade(fn, scope, args);
24992 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
24993 * function call will be the scope provided or the current node. The arguments to the function
24994 * will be the args provided or the current node. If the function returns false at any point,
24995 * the iteration stops.
24996 * @param {Function} fn The function to call
24997 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24998 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25000 eachChild : function(fn, scope, args){
25001 var cs = this.childNodes;
25002 for(var i = 0, len = cs.length; i < len; i++) {
25003 if(fn.call(scope || this, args || cs[i]) === false){
25010 * Finds the first child that has the attribute with the specified value.
25011 * @param {String} attribute The attribute name
25012 * @param {Mixed} value The value to search for
25013 * @return {Node} The found child or null if none was found
25015 findChild : function(attribute, value){
25016 var cs = this.childNodes;
25017 for(var i = 0, len = cs.length; i < len; i++) {
25018 if(cs[i].attributes[attribute] == value){
25026 * Finds the first child by a custom function. The child matches if the function passed
25028 * @param {Function} fn
25029 * @param {Object} scope (optional)
25030 * @return {Node} The found child or null if none was found
25032 findChildBy : function(fn, scope){
25033 var cs = this.childNodes;
25034 for(var i = 0, len = cs.length; i < len; i++) {
25035 if(fn.call(scope||cs[i], cs[i]) === true){
25043 * Sorts this nodes children using the supplied sort function
25044 * @param {Function} fn
25045 * @param {Object} scope (optional)
25047 sort : function(fn, scope){
25048 var cs = this.childNodes;
25049 var len = cs.length;
25051 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25053 for(var i = 0; i < len; i++){
25055 n.previousSibling = cs[i-1];
25056 n.nextSibling = cs[i+1];
25058 this.setFirstChild(n);
25061 this.setLastChild(n);
25068 * Returns true if this node is an ancestor (at any point) of the passed node.
25069 * @param {Node} node
25070 * @return {Boolean}
25072 contains : function(node){
25073 return node.isAncestor(this);
25077 * Returns true if the passed node is an ancestor (at any point) of this node.
25078 * @param {Node} node
25079 * @return {Boolean}
25081 isAncestor : function(node){
25082 var p = this.parentNode;
25092 toString : function(){
25093 return "[Node"+(this.id?" "+this.id:"")+"]";
25097 * Ext JS Library 1.1.1
25098 * Copyright(c) 2006-2007, Ext JS, LLC.
25100 * Originally Released Under LGPL - original licence link has changed is not relivant.
25103 * <script type="text/javascript">
25108 * @extends Roo.Element
25109 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25110 * automatic maintaining of shadow/shim positions.
25111 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25112 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25113 * you can pass a string with a CSS class name. False turns off the shadow.
25114 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25115 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25116 * @cfg {String} cls CSS class to add to the element
25117 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25118 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25120 * @param {Object} config An object with config options.
25121 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25124 Roo.Layer = function(config, existingEl){
25125 config = config || {};
25126 var dh = Roo.DomHelper;
25127 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25129 this.dom = Roo.getDom(existingEl);
25132 var o = config.dh || {tag: "div", cls: "x-layer"};
25133 this.dom = dh.append(pel, o);
25136 this.addClass(config.cls);
25138 this.constrain = config.constrain !== false;
25139 this.visibilityMode = Roo.Element.VISIBILITY;
25141 this.id = this.dom.id = config.id;
25143 this.id = Roo.id(this.dom);
25145 this.zindex = config.zindex || this.getZIndex();
25146 this.position("absolute", this.zindex);
25148 this.shadowOffset = config.shadowOffset || 4;
25149 this.shadow = new Roo.Shadow({
25150 offset : this.shadowOffset,
25151 mode : config.shadow
25154 this.shadowOffset = 0;
25156 this.useShim = config.shim !== false && Roo.useShims;
25157 this.useDisplay = config.useDisplay;
25161 var supr = Roo.Element.prototype;
25163 // shims are shared among layer to keep from having 100 iframes
25166 Roo.extend(Roo.Layer, Roo.Element, {
25168 getZIndex : function(){
25169 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25172 getShim : function(){
25179 var shim = shims.shift();
25181 shim = this.createShim();
25182 shim.enableDisplayMode('block');
25183 shim.dom.style.display = 'none';
25184 shim.dom.style.visibility = 'visible';
25186 var pn = this.dom.parentNode;
25187 if(shim.dom.parentNode != pn){
25188 pn.insertBefore(shim.dom, this.dom);
25190 shim.setStyle('z-index', this.getZIndex()-2);
25195 hideShim : function(){
25197 this.shim.setDisplayed(false);
25198 shims.push(this.shim);
25203 disableShadow : function(){
25205 this.shadowDisabled = true;
25206 this.shadow.hide();
25207 this.lastShadowOffset = this.shadowOffset;
25208 this.shadowOffset = 0;
25212 enableShadow : function(show){
25214 this.shadowDisabled = false;
25215 this.shadowOffset = this.lastShadowOffset;
25216 delete this.lastShadowOffset;
25224 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25225 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25226 sync : function(doShow){
25227 var sw = this.shadow;
25228 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25229 var sh = this.getShim();
25231 var w = this.getWidth(),
25232 h = this.getHeight();
25234 var l = this.getLeft(true),
25235 t = this.getTop(true);
25237 if(sw && !this.shadowDisabled){
25238 if(doShow && !sw.isVisible()){
25241 sw.realign(l, t, w, h);
25247 // fit the shim behind the shadow, so it is shimmed too
25248 var a = sw.adjusts, s = sh.dom.style;
25249 s.left = (Math.min(l, l+a.l))+"px";
25250 s.top = (Math.min(t, t+a.t))+"px";
25251 s.width = (w+a.w)+"px";
25252 s.height = (h+a.h)+"px";
25259 sh.setLeftTop(l, t);
25266 destroy : function(){
25269 this.shadow.hide();
25271 this.removeAllListeners();
25272 var pn = this.dom.parentNode;
25274 pn.removeChild(this.dom);
25276 Roo.Element.uncache(this.id);
25279 remove : function(){
25284 beginUpdate : function(){
25285 this.updating = true;
25289 endUpdate : function(){
25290 this.updating = false;
25295 hideUnders : function(negOffset){
25297 this.shadow.hide();
25303 constrainXY : function(){
25304 if(this.constrain){
25305 var vw = Roo.lib.Dom.getViewWidth(),
25306 vh = Roo.lib.Dom.getViewHeight();
25307 var s = Roo.get(document).getScroll();
25309 var xy = this.getXY();
25310 var x = xy[0], y = xy[1];
25311 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25312 // only move it if it needs it
25314 // first validate right/bottom
25315 if((x + w) > vw+s.left){
25316 x = vw - w - this.shadowOffset;
25319 if((y + h) > vh+s.top){
25320 y = vh - h - this.shadowOffset;
25323 // then make sure top/left isn't negative
25334 var ay = this.avoidY;
25335 if(y <= ay && (y+h) >= ay){
25341 supr.setXY.call(this, xy);
25347 isVisible : function(){
25348 return this.visible;
25352 showAction : function(){
25353 this.visible = true; // track visibility to prevent getStyle calls
25354 if(this.useDisplay === true){
25355 this.setDisplayed("");
25356 }else if(this.lastXY){
25357 supr.setXY.call(this, this.lastXY);
25358 }else if(this.lastLT){
25359 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25364 hideAction : function(){
25365 this.visible = false;
25366 if(this.useDisplay === true){
25367 this.setDisplayed(false);
25369 this.setLeftTop(-10000,-10000);
25373 // overridden Element method
25374 setVisible : function(v, a, d, c, e){
25379 var cb = function(){
25384 }.createDelegate(this);
25385 supr.setVisible.call(this, true, true, d, cb, e);
25388 this.hideUnders(true);
25397 }.createDelegate(this);
25399 supr.setVisible.call(this, v, a, d, cb, e);
25408 storeXY : function(xy){
25409 delete this.lastLT;
25413 storeLeftTop : function(left, top){
25414 delete this.lastXY;
25415 this.lastLT = [left, top];
25419 beforeFx : function(){
25420 this.beforeAction();
25421 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25425 afterFx : function(){
25426 Roo.Layer.superclass.afterFx.apply(this, arguments);
25427 this.sync(this.isVisible());
25431 beforeAction : function(){
25432 if(!this.updating && this.shadow){
25433 this.shadow.hide();
25437 // overridden Element method
25438 setLeft : function(left){
25439 this.storeLeftTop(left, this.getTop(true));
25440 supr.setLeft.apply(this, arguments);
25444 setTop : function(top){
25445 this.storeLeftTop(this.getLeft(true), top);
25446 supr.setTop.apply(this, arguments);
25450 setLeftTop : function(left, top){
25451 this.storeLeftTop(left, top);
25452 supr.setLeftTop.apply(this, arguments);
25456 setXY : function(xy, a, d, c, e){
25458 this.beforeAction();
25460 var cb = this.createCB(c);
25461 supr.setXY.call(this, xy, a, d, cb, e);
25468 createCB : function(c){
25479 // overridden Element method
25480 setX : function(x, a, d, c, e){
25481 this.setXY([x, this.getY()], a, d, c, e);
25484 // overridden Element method
25485 setY : function(y, a, d, c, e){
25486 this.setXY([this.getX(), y], a, d, c, e);
25489 // overridden Element method
25490 setSize : function(w, h, a, d, c, e){
25491 this.beforeAction();
25492 var cb = this.createCB(c);
25493 supr.setSize.call(this, w, h, a, d, cb, e);
25499 // overridden Element method
25500 setWidth : function(w, a, d, c, e){
25501 this.beforeAction();
25502 var cb = this.createCB(c);
25503 supr.setWidth.call(this, w, a, d, cb, e);
25509 // overridden Element method
25510 setHeight : function(h, a, d, c, e){
25511 this.beforeAction();
25512 var cb = this.createCB(c);
25513 supr.setHeight.call(this, h, a, d, cb, e);
25519 // overridden Element method
25520 setBounds : function(x, y, w, h, a, d, c, e){
25521 this.beforeAction();
25522 var cb = this.createCB(c);
25524 this.storeXY([x, y]);
25525 supr.setXY.call(this, [x, y]);
25526 supr.setSize.call(this, w, h, a, d, cb, e);
25529 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25535 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25536 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25537 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25538 * @param {Number} zindex The new z-index to set
25539 * @return {this} The Layer
25541 setZIndex : function(zindex){
25542 this.zindex = zindex;
25543 this.setStyle("z-index", zindex + 2);
25545 this.shadow.setZIndex(zindex + 1);
25548 this.shim.setStyle("z-index", zindex);
25554 * Ext JS Library 1.1.1
25555 * Copyright(c) 2006-2007, Ext JS, LLC.
25557 * Originally Released Under LGPL - original licence link has changed is not relivant.
25560 * <script type="text/javascript">
25565 * @class Roo.Shadow
25566 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25567 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25568 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25570 * Create a new Shadow
25571 * @param {Object} config The config object
25573 Roo.Shadow = function(config){
25574 Roo.apply(this, config);
25575 if(typeof this.mode != "string"){
25576 this.mode = this.defaultMode;
25578 var o = this.offset, a = {h: 0};
25579 var rad = Math.floor(this.offset/2);
25580 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25586 a.l -= this.offset + rad;
25587 a.t -= this.offset + rad;
25598 a.l -= (this.offset - rad);
25599 a.t -= this.offset + rad;
25601 a.w -= (this.offset - rad)*2;
25612 a.l -= (this.offset - rad);
25613 a.t -= (this.offset - rad);
25615 a.w -= (this.offset + rad + 1);
25616 a.h -= (this.offset + rad);
25625 Roo.Shadow.prototype = {
25627 * @cfg {String} mode
25628 * The shadow display mode. Supports the following options:<br />
25629 * sides: Shadow displays on both sides and bottom only<br />
25630 * frame: Shadow displays equally on all four sides<br />
25631 * drop: Traditional bottom-right drop shadow (default)
25634 * @cfg {String} offset
25635 * The number of pixels to offset the shadow from the element (defaults to 4)
25640 defaultMode: "drop",
25643 * Displays the shadow under the target element
25644 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25646 show : function(target){
25647 target = Roo.get(target);
25649 this.el = Roo.Shadow.Pool.pull();
25650 if(this.el.dom.nextSibling != target.dom){
25651 this.el.insertBefore(target);
25654 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25656 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25659 target.getLeft(true),
25660 target.getTop(true),
25664 this.el.dom.style.display = "block";
25668 * Returns true if the shadow is visible, else false
25670 isVisible : function(){
25671 return this.el ? true : false;
25675 * Direct alignment when values are already available. Show must be called at least once before
25676 * calling this method to ensure it is initialized.
25677 * @param {Number} left The target element left position
25678 * @param {Number} top The target element top position
25679 * @param {Number} width The target element width
25680 * @param {Number} height The target element height
25682 realign : function(l, t, w, h){
25686 var a = this.adjusts, d = this.el.dom, s = d.style;
25688 s.left = (l+a.l)+"px";
25689 s.top = (t+a.t)+"px";
25690 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25692 if(s.width != sws || s.height != shs){
25696 var cn = d.childNodes;
25697 var sww = Math.max(0, (sw-12))+"px";
25698 cn[0].childNodes[1].style.width = sww;
25699 cn[1].childNodes[1].style.width = sww;
25700 cn[2].childNodes[1].style.width = sww;
25701 cn[1].style.height = Math.max(0, (sh-12))+"px";
25707 * Hides this shadow
25711 this.el.dom.style.display = "none";
25712 Roo.Shadow.Pool.push(this.el);
25718 * Adjust the z-index of this shadow
25719 * @param {Number} zindex The new z-index
25721 setZIndex : function(z){
25724 this.el.setStyle("z-index", z);
25729 // Private utility class that manages the internal Shadow cache
25730 Roo.Shadow.Pool = function(){
25732 var markup = Roo.isIE ?
25733 '<div class="x-ie-shadow"></div>' :
25734 '<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>';
25737 var sh = p.shift();
25739 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25740 sh.autoBoxAdjust = false;
25745 push : function(sh){
25751 * Ext JS Library 1.1.1
25752 * Copyright(c) 2006-2007, Ext JS, LLC.
25754 * Originally Released Under LGPL - original licence link has changed is not relivant.
25757 * <script type="text/javascript">
25762 * @class Roo.SplitBar
25763 * @extends Roo.util.Observable
25764 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25768 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25769 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25770 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25771 split.minSize = 100;
25772 split.maxSize = 600;
25773 split.animate = true;
25774 split.on('moved', splitterMoved);
25777 * Create a new SplitBar
25778 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25779 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25780 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25781 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25782 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25783 position of the SplitBar).
25785 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25788 this.el = Roo.get(dragElement, true);
25789 this.el.dom.unselectable = "on";
25791 this.resizingEl = Roo.get(resizingElement, true);
25795 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25796 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25799 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25802 * The minimum size of the resizing element. (Defaults to 0)
25808 * The maximum size of the resizing element. (Defaults to 2000)
25811 this.maxSize = 2000;
25814 * Whether to animate the transition to the new size
25817 this.animate = false;
25820 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25823 this.useShim = false;
25828 if(!existingProxy){
25830 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25832 this.proxy = Roo.get(existingProxy).dom;
25835 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25838 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25841 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25844 this.dragSpecs = {};
25847 * @private The adapter to use to positon and resize elements
25849 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25850 this.adapter.init(this);
25852 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25854 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25855 this.el.addClass("x-splitbar-h");
25858 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25859 this.el.addClass("x-splitbar-v");
25865 * Fires when the splitter is moved (alias for {@link #event-moved})
25866 * @param {Roo.SplitBar} this
25867 * @param {Number} newSize the new width or height
25872 * Fires when the splitter is moved
25873 * @param {Roo.SplitBar} this
25874 * @param {Number} newSize the new width or height
25878 * @event beforeresize
25879 * Fires before the splitter is dragged
25880 * @param {Roo.SplitBar} this
25882 "beforeresize" : true,
25884 "beforeapply" : true
25887 Roo.util.Observable.call(this);
25890 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
25891 onStartProxyDrag : function(x, y){
25892 this.fireEvent("beforeresize", this);
25894 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
25896 o.enableDisplayMode("block");
25897 // all splitbars share the same overlay
25898 Roo.SplitBar.prototype.overlay = o;
25900 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
25901 this.overlay.show();
25902 Roo.get(this.proxy).setDisplayed("block");
25903 var size = this.adapter.getElementSize(this);
25904 this.activeMinSize = this.getMinimumSize();;
25905 this.activeMaxSize = this.getMaximumSize();;
25906 var c1 = size - this.activeMinSize;
25907 var c2 = Math.max(this.activeMaxSize - size, 0);
25908 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25909 this.dd.resetConstraints();
25910 this.dd.setXConstraint(
25911 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
25912 this.placement == Roo.SplitBar.LEFT ? c2 : c1
25914 this.dd.setYConstraint(0, 0);
25916 this.dd.resetConstraints();
25917 this.dd.setXConstraint(0, 0);
25918 this.dd.setYConstraint(
25919 this.placement == Roo.SplitBar.TOP ? c1 : c2,
25920 this.placement == Roo.SplitBar.TOP ? c2 : c1
25923 this.dragSpecs.startSize = size;
25924 this.dragSpecs.startPoint = [x, y];
25925 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
25929 * @private Called after the drag operation by the DDProxy
25931 onEndProxyDrag : function(e){
25932 Roo.get(this.proxy).setDisplayed(false);
25933 var endPoint = Roo.lib.Event.getXY(e);
25935 this.overlay.hide();
25938 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25939 newSize = this.dragSpecs.startSize +
25940 (this.placement == Roo.SplitBar.LEFT ?
25941 endPoint[0] - this.dragSpecs.startPoint[0] :
25942 this.dragSpecs.startPoint[0] - endPoint[0]
25945 newSize = this.dragSpecs.startSize +
25946 (this.placement == Roo.SplitBar.TOP ?
25947 endPoint[1] - this.dragSpecs.startPoint[1] :
25948 this.dragSpecs.startPoint[1] - endPoint[1]
25951 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
25952 if(newSize != this.dragSpecs.startSize){
25953 if(this.fireEvent('beforeapply', this, newSize) !== false){
25954 this.adapter.setElementSize(this, newSize);
25955 this.fireEvent("moved", this, newSize);
25956 this.fireEvent("resize", this, newSize);
25962 * Get the adapter this SplitBar uses
25963 * @return The adapter object
25965 getAdapter : function(){
25966 return this.adapter;
25970 * Set the adapter this SplitBar uses
25971 * @param {Object} adapter A SplitBar adapter object
25973 setAdapter : function(adapter){
25974 this.adapter = adapter;
25975 this.adapter.init(this);
25979 * Gets the minimum size for the resizing element
25980 * @return {Number} The minimum size
25982 getMinimumSize : function(){
25983 return this.minSize;
25987 * Sets the minimum size for the resizing element
25988 * @param {Number} minSize The minimum size
25990 setMinimumSize : function(minSize){
25991 this.minSize = minSize;
25995 * Gets the maximum size for the resizing element
25996 * @return {Number} The maximum size
25998 getMaximumSize : function(){
25999 return this.maxSize;
26003 * Sets the maximum size for the resizing element
26004 * @param {Number} maxSize The maximum size
26006 setMaximumSize : function(maxSize){
26007 this.maxSize = maxSize;
26011 * Sets the initialize size for the resizing element
26012 * @param {Number} size The initial size
26014 setCurrentSize : function(size){
26015 var oldAnimate = this.animate;
26016 this.animate = false;
26017 this.adapter.setElementSize(this, size);
26018 this.animate = oldAnimate;
26022 * Destroy this splitbar.
26023 * @param {Boolean} removeEl True to remove the element
26025 destroy : function(removeEl){
26027 this.shim.remove();
26030 this.proxy.parentNode.removeChild(this.proxy);
26038 * @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.
26040 Roo.SplitBar.createProxy = function(dir){
26041 var proxy = new Roo.Element(document.createElement("div"));
26042 proxy.unselectable();
26043 var cls = 'x-splitbar-proxy';
26044 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26045 document.body.appendChild(proxy.dom);
26050 * @class Roo.SplitBar.BasicLayoutAdapter
26051 * Default Adapter. It assumes the splitter and resizing element are not positioned
26052 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26054 Roo.SplitBar.BasicLayoutAdapter = function(){
26057 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26058 // do nothing for now
26059 init : function(s){
26063 * Called before drag operations to get the current size of the resizing element.
26064 * @param {Roo.SplitBar} s The SplitBar using this adapter
26066 getElementSize : function(s){
26067 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26068 return s.resizingEl.getWidth();
26070 return s.resizingEl.getHeight();
26075 * Called after drag operations to set the size of the resizing element.
26076 * @param {Roo.SplitBar} s The SplitBar using this adapter
26077 * @param {Number} newSize The new size to set
26078 * @param {Function} onComplete A function to be invoked when resizing is complete
26080 setElementSize : function(s, newSize, onComplete){
26081 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26083 s.resizingEl.setWidth(newSize);
26085 onComplete(s, newSize);
26088 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26093 s.resizingEl.setHeight(newSize);
26095 onComplete(s, newSize);
26098 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26105 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26106 * @extends Roo.SplitBar.BasicLayoutAdapter
26107 * Adapter that moves the splitter element to align with the resized sizing element.
26108 * Used with an absolute positioned SplitBar.
26109 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26110 * document.body, make sure you assign an id to the body element.
26112 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26113 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26114 this.container = Roo.get(container);
26117 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26118 init : function(s){
26119 this.basic.init(s);
26122 getElementSize : function(s){
26123 return this.basic.getElementSize(s);
26126 setElementSize : function(s, newSize, onComplete){
26127 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26130 moveSplitter : function(s){
26131 var yes = Roo.SplitBar;
26132 switch(s.placement){
26134 s.el.setX(s.resizingEl.getRight());
26137 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26140 s.el.setY(s.resizingEl.getBottom());
26143 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26150 * Orientation constant - Create a vertical SplitBar
26154 Roo.SplitBar.VERTICAL = 1;
26157 * Orientation constant - Create a horizontal SplitBar
26161 Roo.SplitBar.HORIZONTAL = 2;
26164 * Placement constant - The resizing element is to the left of the splitter element
26168 Roo.SplitBar.LEFT = 1;
26171 * Placement constant - The resizing element is to the right of the splitter element
26175 Roo.SplitBar.RIGHT = 2;
26178 * Placement constant - The resizing element is positioned above the splitter element
26182 Roo.SplitBar.TOP = 3;
26185 * Placement constant - The resizing element is positioned under splitter element
26189 Roo.SplitBar.BOTTOM = 4;
26192 * Ext JS Library 1.1.1
26193 * Copyright(c) 2006-2007, Ext JS, LLC.
26195 * Originally Released Under LGPL - original licence link has changed is not relivant.
26198 * <script type="text/javascript">
26203 * @extends Roo.util.Observable
26204 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26205 * This class also supports single and multi selection modes. <br>
26206 * Create a data model bound view:
26208 var store = new Roo.data.Store(...);
26210 var view = new Roo.View({
26212 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26214 singleSelect: true,
26215 selectedClass: "ydataview-selected",
26219 // listen for node click?
26220 view.on("click", function(vw, index, node, e){
26221 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26225 dataModel.load("foobar.xml");
26227 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26229 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26230 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26232 * Note: old style constructor is still suported (container, template, config)
26235 * Create a new View
26236 * @param {Object} config The config object
26239 Roo.View = function(config, depreciated_tpl, depreciated_config){
26241 this.parent = false;
26243 if (typeof(depreciated_tpl) == 'undefined') {
26244 // new way.. - universal constructor.
26245 Roo.apply(this, config);
26246 this.el = Roo.get(this.el);
26249 this.el = Roo.get(config);
26250 this.tpl = depreciated_tpl;
26251 Roo.apply(this, depreciated_config);
26253 this.wrapEl = this.el.wrap().wrap();
26254 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26257 if(typeof(this.tpl) == "string"){
26258 this.tpl = new Roo.Template(this.tpl);
26260 // support xtype ctors..
26261 this.tpl = new Roo.factory(this.tpl, Roo);
26265 this.tpl.compile();
26270 * @event beforeclick
26271 * Fires before a click is processed. Returns false to cancel the default action.
26272 * @param {Roo.View} this
26273 * @param {Number} index The index of the target node
26274 * @param {HTMLElement} node The target node
26275 * @param {Roo.EventObject} e The raw event object
26277 "beforeclick" : true,
26280 * Fires when a template node is clicked.
26281 * @param {Roo.View} this
26282 * @param {Number} index The index of the target node
26283 * @param {HTMLElement} node The target node
26284 * @param {Roo.EventObject} e The raw event object
26289 * Fires when a template node is double clicked.
26290 * @param {Roo.View} this
26291 * @param {Number} index The index of the target node
26292 * @param {HTMLElement} node The target node
26293 * @param {Roo.EventObject} e The raw event object
26297 * @event contextmenu
26298 * Fires when a template node is right clicked.
26299 * @param {Roo.View} this
26300 * @param {Number} index The index of the target node
26301 * @param {HTMLElement} node The target node
26302 * @param {Roo.EventObject} e The raw event object
26304 "contextmenu" : true,
26306 * @event selectionchange
26307 * Fires when the selected nodes change.
26308 * @param {Roo.View} this
26309 * @param {Array} selections Array of the selected nodes
26311 "selectionchange" : true,
26314 * @event beforeselect
26315 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26316 * @param {Roo.View} this
26317 * @param {HTMLElement} node The node to be selected
26318 * @param {Array} selections Array of currently selected nodes
26320 "beforeselect" : true,
26322 * @event preparedata
26323 * Fires on every row to render, to allow you to change the data.
26324 * @param {Roo.View} this
26325 * @param {Object} data to be rendered (change this)
26327 "preparedata" : true
26335 "click": this.onClick,
26336 "dblclick": this.onDblClick,
26337 "contextmenu": this.onContextMenu,
26341 this.selections = [];
26343 this.cmp = new Roo.CompositeElementLite([]);
26345 this.store = Roo.factory(this.store, Roo.data);
26346 this.setStore(this.store, true);
26349 if ( this.footer && this.footer.xtype) {
26351 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26353 this.footer.dataSource = this.store;
26354 this.footer.container = fctr;
26355 this.footer = Roo.factory(this.footer, Roo);
26356 fctr.insertFirst(this.el);
26358 // this is a bit insane - as the paging toolbar seems to detach the el..
26359 // dom.parentNode.parentNode.parentNode
26360 // they get detached?
26364 Roo.View.superclass.constructor.call(this);
26369 Roo.extend(Roo.View, Roo.util.Observable, {
26372 * @cfg {Roo.data.Store} store Data store to load data from.
26377 * @cfg {String|Roo.Element} el The container element.
26382 * @cfg {String|Roo.Template} tpl The template used by this View
26386 * @cfg {String} dataName the named area of the template to use as the data area
26387 * Works with domtemplates roo-name="name"
26391 * @cfg {String} selectedClass The css class to add to selected nodes
26393 selectedClass : "x-view-selected",
26395 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26400 * @cfg {String} text to display on mask (default Loading)
26404 * @cfg {Boolean} multiSelect Allow multiple selection
26406 multiSelect : false,
26408 * @cfg {Boolean} singleSelect Allow single selection
26410 singleSelect: false,
26413 * @cfg {Boolean} toggleSelect - selecting
26415 toggleSelect : false,
26418 * @cfg {Boolean} tickable - selecting
26423 * Returns the element this view is bound to.
26424 * @return {Roo.Element}
26426 getEl : function(){
26427 return this.wrapEl;
26433 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26435 refresh : function(){
26436 //Roo.log('refresh');
26439 // if we are using something like 'domtemplate', then
26440 // the what gets used is:
26441 // t.applySubtemplate(NAME, data, wrapping data..)
26442 // the outer template then get' applied with
26443 // the store 'extra data'
26444 // and the body get's added to the
26445 // roo-name="data" node?
26446 // <span class='roo-tpl-{name}'></span> ?????
26450 this.clearSelections();
26451 this.el.update("");
26453 var records = this.store.getRange();
26454 if(records.length < 1) {
26456 // is this valid?? = should it render a template??
26458 this.el.update(this.emptyText);
26462 if (this.dataName) {
26463 this.el.update(t.apply(this.store.meta)); //????
26464 el = this.el.child('.roo-tpl-' + this.dataName);
26467 for(var i = 0, len = records.length; i < len; i++){
26468 var data = this.prepareData(records[i].data, i, records[i]);
26469 this.fireEvent("preparedata", this, data, i, records[i]);
26471 var d = Roo.apply({}, data);
26474 Roo.apply(d, {'roo-id' : Roo.id()});
26478 Roo.each(this.parent.item, function(item){
26479 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26482 Roo.apply(d, {'roo-data-checked' : 'checked'});
26486 html[html.length] = Roo.util.Format.trim(
26488 t.applySubtemplate(this.dataName, d, this.store.meta) :
26495 el.update(html.join(""));
26496 this.nodes = el.dom.childNodes;
26497 this.updateIndexes(0);
26502 * Function to override to reformat the data that is sent to
26503 * the template for each node.
26504 * DEPRICATED - use the preparedata event handler.
26505 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26506 * a JSON object for an UpdateManager bound view).
26508 prepareData : function(data, index, record)
26510 this.fireEvent("preparedata", this, data, index, record);
26514 onUpdate : function(ds, record){
26515 // Roo.log('on update');
26516 this.clearSelections();
26517 var index = this.store.indexOf(record);
26518 var n = this.nodes[index];
26519 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26520 n.parentNode.removeChild(n);
26521 this.updateIndexes(index, index);
26527 onAdd : function(ds, records, index)
26529 //Roo.log(['on Add', ds, records, index] );
26530 this.clearSelections();
26531 if(this.nodes.length == 0){
26535 var n = this.nodes[index];
26536 for(var i = 0, len = records.length; i < len; i++){
26537 var d = this.prepareData(records[i].data, i, records[i]);
26539 this.tpl.insertBefore(n, d);
26542 this.tpl.append(this.el, d);
26545 this.updateIndexes(index);
26548 onRemove : function(ds, record, index){
26549 // Roo.log('onRemove');
26550 this.clearSelections();
26551 var el = this.dataName ?
26552 this.el.child('.roo-tpl-' + this.dataName) :
26555 el.dom.removeChild(this.nodes[index]);
26556 this.updateIndexes(index);
26560 * Refresh an individual node.
26561 * @param {Number} index
26563 refreshNode : function(index){
26564 this.onUpdate(this.store, this.store.getAt(index));
26567 updateIndexes : function(startIndex, endIndex){
26568 var ns = this.nodes;
26569 startIndex = startIndex || 0;
26570 endIndex = endIndex || ns.length - 1;
26571 for(var i = startIndex; i <= endIndex; i++){
26572 ns[i].nodeIndex = i;
26577 * Changes the data store this view uses and refresh the view.
26578 * @param {Store} store
26580 setStore : function(store, initial){
26581 if(!initial && this.store){
26582 this.store.un("datachanged", this.refresh);
26583 this.store.un("add", this.onAdd);
26584 this.store.un("remove", this.onRemove);
26585 this.store.un("update", this.onUpdate);
26586 this.store.un("clear", this.refresh);
26587 this.store.un("beforeload", this.onBeforeLoad);
26588 this.store.un("load", this.onLoad);
26589 this.store.un("loadexception", this.onLoad);
26593 store.on("datachanged", this.refresh, this);
26594 store.on("add", this.onAdd, this);
26595 store.on("remove", this.onRemove, this);
26596 store.on("update", this.onUpdate, this);
26597 store.on("clear", this.refresh, this);
26598 store.on("beforeload", this.onBeforeLoad, this);
26599 store.on("load", this.onLoad, this);
26600 store.on("loadexception", this.onLoad, this);
26608 * onbeforeLoad - masks the loading area.
26611 onBeforeLoad : function(store,opts)
26613 //Roo.log('onBeforeLoad');
26615 this.el.update("");
26617 this.el.mask(this.mask ? this.mask : "Loading" );
26619 onLoad : function ()
26626 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26627 * @param {HTMLElement} node
26628 * @return {HTMLElement} The template node
26630 findItemFromChild : function(node){
26631 var el = this.dataName ?
26632 this.el.child('.roo-tpl-' + this.dataName,true) :
26635 if(!node || node.parentNode == el){
26638 var p = node.parentNode;
26639 while(p && p != el){
26640 if(p.parentNode == el){
26649 onClick : function(e){
26650 var item = this.findItemFromChild(e.getTarget());
26652 var index = this.indexOf(item);
26653 if(this.onItemClick(item, index, e) !== false){
26654 this.fireEvent("click", this, index, item, e);
26657 this.clearSelections();
26662 onContextMenu : function(e){
26663 var item = this.findItemFromChild(e.getTarget());
26665 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26670 onDblClick : function(e){
26671 var item = this.findItemFromChild(e.getTarget());
26673 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26677 onItemClick : function(item, index, e)
26679 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26682 if (this.toggleSelect) {
26683 var m = this.isSelected(item) ? 'unselect' : 'select';
26686 _t[m](item, true, false);
26689 if(this.multiSelect || this.singleSelect){
26690 if(this.multiSelect && e.shiftKey && this.lastSelection){
26691 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26693 this.select(item, this.multiSelect && e.ctrlKey);
26694 this.lastSelection = item;
26697 if(!this.tickable){
26698 e.preventDefault();
26706 * Get the number of selected nodes.
26709 getSelectionCount : function(){
26710 return this.selections.length;
26714 * Get the currently selected nodes.
26715 * @return {Array} An array of HTMLElements
26717 getSelectedNodes : function(){
26718 return this.selections;
26722 * Get the indexes of the selected nodes.
26725 getSelectedIndexes : function(){
26726 var indexes = [], s = this.selections;
26727 for(var i = 0, len = s.length; i < len; i++){
26728 indexes.push(s[i].nodeIndex);
26734 * Clear all selections
26735 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26737 clearSelections : function(suppressEvent){
26738 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26739 this.cmp.elements = this.selections;
26740 this.cmp.removeClass(this.selectedClass);
26741 this.selections = [];
26742 if(!suppressEvent){
26743 this.fireEvent("selectionchange", this, this.selections);
26749 * Returns true if the passed node is selected
26750 * @param {HTMLElement/Number} node The node or node index
26751 * @return {Boolean}
26753 isSelected : function(node){
26754 var s = this.selections;
26758 node = this.getNode(node);
26759 return s.indexOf(node) !== -1;
26764 * @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
26765 * @param {Boolean} keepExisting (optional) true to keep existing selections
26766 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26768 select : function(nodeInfo, keepExisting, suppressEvent){
26769 if(nodeInfo instanceof Array){
26771 this.clearSelections(true);
26773 for(var i = 0, len = nodeInfo.length; i < len; i++){
26774 this.select(nodeInfo[i], true, true);
26778 var node = this.getNode(nodeInfo);
26779 if(!node || this.isSelected(node)){
26780 return; // already selected.
26783 this.clearSelections(true);
26786 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26787 Roo.fly(node).addClass(this.selectedClass);
26788 this.selections.push(node);
26789 if(!suppressEvent){
26790 this.fireEvent("selectionchange", this, this.selections);
26798 * @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
26799 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26800 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26802 unselect : function(nodeInfo, keepExisting, suppressEvent)
26804 if(nodeInfo instanceof Array){
26805 Roo.each(this.selections, function(s) {
26806 this.unselect(s, nodeInfo);
26810 var node = this.getNode(nodeInfo);
26811 if(!node || !this.isSelected(node)){
26812 //Roo.log("not selected");
26813 return; // not selected.
26817 Roo.each(this.selections, function(s) {
26819 Roo.fly(node).removeClass(this.selectedClass);
26826 this.selections= ns;
26827 this.fireEvent("selectionchange", this, this.selections);
26831 * Gets a template node.
26832 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26833 * @return {HTMLElement} The node or null if it wasn't found
26835 getNode : function(nodeInfo){
26836 if(typeof nodeInfo == "string"){
26837 return document.getElementById(nodeInfo);
26838 }else if(typeof nodeInfo == "number"){
26839 return this.nodes[nodeInfo];
26845 * Gets a range template nodes.
26846 * @param {Number} startIndex
26847 * @param {Number} endIndex
26848 * @return {Array} An array of nodes
26850 getNodes : function(start, end){
26851 var ns = this.nodes;
26852 start = start || 0;
26853 end = typeof end == "undefined" ? ns.length - 1 : end;
26856 for(var i = start; i <= end; i++){
26860 for(var i = start; i >= end; i--){
26868 * Finds the index of the passed node
26869 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26870 * @return {Number} The index of the node or -1
26872 indexOf : function(node){
26873 node = this.getNode(node);
26874 if(typeof node.nodeIndex == "number"){
26875 return node.nodeIndex;
26877 var ns = this.nodes;
26878 for(var i = 0, len = ns.length; i < len; i++){
26888 * Ext JS Library 1.1.1
26889 * Copyright(c) 2006-2007, Ext JS, LLC.
26891 * Originally Released Under LGPL - original licence link has changed is not relivant.
26894 * <script type="text/javascript">
26898 * @class Roo.JsonView
26899 * @extends Roo.View
26900 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
26902 var view = new Roo.JsonView({
26903 container: "my-element",
26904 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
26909 // listen for node click?
26910 view.on("click", function(vw, index, node, e){
26911 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26914 // direct load of JSON data
26915 view.load("foobar.php");
26917 // Example from my blog list
26918 var tpl = new Roo.Template(
26919 '<div class="entry">' +
26920 '<a class="entry-title" href="{link}">{title}</a>' +
26921 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
26922 "</div><hr />"
26925 var moreView = new Roo.JsonView({
26926 container : "entry-list",
26930 moreView.on("beforerender", this.sortEntries, this);
26932 url: "/blog/get-posts.php",
26933 params: "allposts=true",
26934 text: "Loading Blog Entries..."
26938 * Note: old code is supported with arguments : (container, template, config)
26942 * Create a new JsonView
26944 * @param {Object} config The config object
26947 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
26950 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
26952 var um = this.el.getUpdateManager();
26953 um.setRenderer(this);
26954 um.on("update", this.onLoad, this);
26955 um.on("failure", this.onLoadException, this);
26958 * @event beforerender
26959 * Fires before rendering of the downloaded JSON data.
26960 * @param {Roo.JsonView} this
26961 * @param {Object} data The JSON data loaded
26965 * Fires when data is loaded.
26966 * @param {Roo.JsonView} this
26967 * @param {Object} data The JSON data loaded
26968 * @param {Object} response The raw Connect response object
26971 * @event loadexception
26972 * Fires when loading fails.
26973 * @param {Roo.JsonView} this
26974 * @param {Object} response The raw Connect response object
26977 'beforerender' : true,
26979 'loadexception' : true
26982 Roo.extend(Roo.JsonView, Roo.View, {
26984 * @type {String} The root property in the loaded JSON object that contains the data
26989 * Refreshes the view.
26991 refresh : function(){
26992 this.clearSelections();
26993 this.el.update("");
26995 var o = this.jsonData;
26996 if(o && o.length > 0){
26997 for(var i = 0, len = o.length; i < len; i++){
26998 var data = this.prepareData(o[i], i, o);
26999 html[html.length] = this.tpl.apply(data);
27002 html.push(this.emptyText);
27004 this.el.update(html.join(""));
27005 this.nodes = this.el.dom.childNodes;
27006 this.updateIndexes(0);
27010 * 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.
27011 * @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:
27014 url: "your-url.php",
27015 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27016 callback: yourFunction,
27017 scope: yourObject, //(optional scope)
27020 text: "Loading...",
27025 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27026 * 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.
27027 * @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}
27028 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27029 * @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.
27032 var um = this.el.getUpdateManager();
27033 um.update.apply(um, arguments);
27036 render : function(el, response){
27037 this.clearSelections();
27038 this.el.update("");
27041 o = Roo.util.JSON.decode(response.responseText);
27044 o = o[this.jsonRoot];
27049 * The current JSON data or null
27052 this.beforeRender();
27057 * Get the number of records in the current JSON dataset
27060 getCount : function(){
27061 return this.jsonData ? this.jsonData.length : 0;
27065 * Returns the JSON object for the specified node(s)
27066 * @param {HTMLElement/Array} node The node or an array of nodes
27067 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27068 * you get the JSON object for the node
27070 getNodeData : function(node){
27071 if(node instanceof Array){
27073 for(var i = 0, len = node.length; i < len; i++){
27074 data.push(this.getNodeData(node[i]));
27078 return this.jsonData[this.indexOf(node)] || null;
27081 beforeRender : function(){
27082 this.snapshot = this.jsonData;
27084 this.sort.apply(this, this.sortInfo);
27086 this.fireEvent("beforerender", this, this.jsonData);
27089 onLoad : function(el, o){
27090 this.fireEvent("load", this, this.jsonData, o);
27093 onLoadException : function(el, o){
27094 this.fireEvent("loadexception", this, o);
27098 * Filter the data by a specific property.
27099 * @param {String} property A property on your JSON objects
27100 * @param {String/RegExp} value Either string that the property values
27101 * should start with, or a RegExp to test against the property
27103 filter : function(property, value){
27106 var ss = this.snapshot;
27107 if(typeof value == "string"){
27108 var vlen = value.length;
27110 this.clearFilter();
27113 value = value.toLowerCase();
27114 for(var i = 0, len = ss.length; i < len; i++){
27116 if(o[property].substr(0, vlen).toLowerCase() == value){
27120 } else if(value.exec){ // regex?
27121 for(var i = 0, len = ss.length; i < len; i++){
27123 if(value.test(o[property])){
27130 this.jsonData = data;
27136 * Filter by a function. The passed function will be called with each
27137 * object in the current dataset. If the function returns true the value is kept,
27138 * otherwise it is filtered.
27139 * @param {Function} fn
27140 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27142 filterBy : function(fn, scope){
27145 var ss = this.snapshot;
27146 for(var i = 0, len = ss.length; i < len; i++){
27148 if(fn.call(scope || this, o)){
27152 this.jsonData = data;
27158 * Clears the current filter.
27160 clearFilter : function(){
27161 if(this.snapshot && this.jsonData != this.snapshot){
27162 this.jsonData = this.snapshot;
27169 * Sorts the data for this view and refreshes it.
27170 * @param {String} property A property on your JSON objects to sort on
27171 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27172 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27174 sort : function(property, dir, sortType){
27175 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27178 var dsc = dir && dir.toLowerCase() == "desc";
27179 var f = function(o1, o2){
27180 var v1 = sortType ? sortType(o1[p]) : o1[p];
27181 var v2 = sortType ? sortType(o2[p]) : o2[p];
27184 return dsc ? +1 : -1;
27185 } else if(v1 > v2){
27186 return dsc ? -1 : +1;
27191 this.jsonData.sort(f);
27193 if(this.jsonData != this.snapshot){
27194 this.snapshot.sort(f);
27200 * Ext JS Library 1.1.1
27201 * Copyright(c) 2006-2007, Ext JS, LLC.
27203 * Originally Released Under LGPL - original licence link has changed is not relivant.
27206 * <script type="text/javascript">
27211 * @class Roo.ColorPalette
27212 * @extends Roo.Component
27213 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27214 * Here's an example of typical usage:
27216 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27217 cp.render('my-div');
27219 cp.on('select', function(palette, selColor){
27220 // do something with selColor
27224 * Create a new ColorPalette
27225 * @param {Object} config The config object
27227 Roo.ColorPalette = function(config){
27228 Roo.ColorPalette.superclass.constructor.call(this, config);
27232 * Fires when a color is selected
27233 * @param {ColorPalette} this
27234 * @param {String} color The 6-digit color hex code (without the # symbol)
27240 this.on("select", this.handler, this.scope, true);
27243 Roo.extend(Roo.ColorPalette, Roo.Component, {
27245 * @cfg {String} itemCls
27246 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27248 itemCls : "x-color-palette",
27250 * @cfg {String} value
27251 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27252 * the hex codes are case-sensitive.
27255 clickEvent:'click',
27257 ctype: "Roo.ColorPalette",
27260 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27262 allowReselect : false,
27265 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27266 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27267 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27268 * of colors with the width setting until the box is symmetrical.</p>
27269 * <p>You can override individual colors if needed:</p>
27271 var cp = new Roo.ColorPalette();
27272 cp.colors[0] = "FF0000"; // change the first box to red
27275 Or you can provide a custom array of your own for complete control:
27277 var cp = new Roo.ColorPalette();
27278 cp.colors = ["000000", "993300", "333300"];
27283 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27284 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27285 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27286 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27287 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27291 onRender : function(container, position){
27292 var t = new Roo.MasterTemplate(
27293 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27295 var c = this.colors;
27296 for(var i = 0, len = c.length; i < len; i++){
27299 var el = document.createElement("div");
27300 el.className = this.itemCls;
27302 container.dom.insertBefore(el, position);
27303 this.el = Roo.get(el);
27304 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27305 if(this.clickEvent != 'click'){
27306 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27311 afterRender : function(){
27312 Roo.ColorPalette.superclass.afterRender.call(this);
27314 var s = this.value;
27321 handleClick : function(e, t){
27322 e.preventDefault();
27323 if(!this.disabled){
27324 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27325 this.select(c.toUpperCase());
27330 * Selects the specified color in the palette (fires the select event)
27331 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27333 select : function(color){
27334 color = color.replace("#", "");
27335 if(color != this.value || this.allowReselect){
27338 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27340 el.child("a.color-"+color).addClass("x-color-palette-sel");
27341 this.value = color;
27342 this.fireEvent("select", this, color);
27347 * Ext JS Library 1.1.1
27348 * Copyright(c) 2006-2007, Ext JS, LLC.
27350 * Originally Released Under LGPL - original licence link has changed is not relivant.
27353 * <script type="text/javascript">
27357 * @class Roo.DatePicker
27358 * @extends Roo.Component
27359 * Simple date picker class.
27361 * Create a new DatePicker
27362 * @param {Object} config The config object
27364 Roo.DatePicker = function(config){
27365 Roo.DatePicker.superclass.constructor.call(this, config);
27367 this.value = config && config.value ?
27368 config.value.clearTime() : new Date().clearTime();
27373 * Fires when a date is selected
27374 * @param {DatePicker} this
27375 * @param {Date} date The selected date
27379 * @event monthchange
27380 * Fires when the displayed month changes
27381 * @param {DatePicker} this
27382 * @param {Date} date The selected month
27384 'monthchange': true
27388 this.on("select", this.handler, this.scope || this);
27390 // build the disabledDatesRE
27391 if(!this.disabledDatesRE && this.disabledDates){
27392 var dd = this.disabledDates;
27394 for(var i = 0; i < dd.length; i++){
27396 if(i != dd.length-1) {
27400 this.disabledDatesRE = new RegExp(re + ")");
27404 Roo.extend(Roo.DatePicker, Roo.Component, {
27406 * @cfg {String} todayText
27407 * The text to display on the button that selects the current date (defaults to "Today")
27409 todayText : "Today",
27411 * @cfg {String} okText
27412 * The text to display on the ok button
27414 okText : " OK ", //   to give the user extra clicking room
27416 * @cfg {String} cancelText
27417 * The text to display on the cancel button
27419 cancelText : "Cancel",
27421 * @cfg {String} todayTip
27422 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27424 todayTip : "{0} (Spacebar)",
27426 * @cfg {Date} minDate
27427 * Minimum allowable date (JavaScript date object, defaults to null)
27431 * @cfg {Date} maxDate
27432 * Maximum allowable date (JavaScript date object, defaults to null)
27436 * @cfg {String} minText
27437 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27439 minText : "This date is before the minimum date",
27441 * @cfg {String} maxText
27442 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27444 maxText : "This date is after the maximum date",
27446 * @cfg {String} format
27447 * The default date format string which can be overriden for localization support. The format must be
27448 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27452 * @cfg {Array} disabledDays
27453 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27455 disabledDays : null,
27457 * @cfg {String} disabledDaysText
27458 * The tooltip to display when the date falls on a disabled day (defaults to "")
27460 disabledDaysText : "",
27462 * @cfg {RegExp} disabledDatesRE
27463 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27465 disabledDatesRE : null,
27467 * @cfg {String} disabledDatesText
27468 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27470 disabledDatesText : "",
27472 * @cfg {Boolean} constrainToViewport
27473 * True to constrain the date picker to the viewport (defaults to true)
27475 constrainToViewport : true,
27477 * @cfg {Array} monthNames
27478 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27480 monthNames : Date.monthNames,
27482 * @cfg {Array} dayNames
27483 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27485 dayNames : Date.dayNames,
27487 * @cfg {String} nextText
27488 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27490 nextText: 'Next Month (Control+Right)',
27492 * @cfg {String} prevText
27493 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27495 prevText: 'Previous Month (Control+Left)',
27497 * @cfg {String} monthYearText
27498 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27500 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27502 * @cfg {Number} startDay
27503 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27507 * @cfg {Bool} showClear
27508 * Show a clear button (usefull for date form elements that can be blank.)
27514 * Sets the value of the date field
27515 * @param {Date} value The date to set
27517 setValue : function(value){
27518 var old = this.value;
27520 if (typeof(value) == 'string') {
27522 value = Date.parseDate(value, this.format);
27525 value = new Date();
27528 this.value = value.clearTime(true);
27530 this.update(this.value);
27535 * Gets the current selected value of the date field
27536 * @return {Date} The selected date
27538 getValue : function(){
27543 focus : function(){
27545 this.update(this.activeDate);
27550 onRender : function(container, position){
27553 '<table cellspacing="0">',
27554 '<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>',
27555 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27556 var dn = this.dayNames;
27557 for(var i = 0; i < 7; i++){
27558 var d = this.startDay+i;
27562 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27564 m[m.length] = "</tr></thead><tbody><tr>";
27565 for(var i = 0; i < 42; i++) {
27566 if(i % 7 == 0 && i != 0){
27567 m[m.length] = "</tr><tr>";
27569 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27571 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27572 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27574 var el = document.createElement("div");
27575 el.className = "x-date-picker";
27576 el.innerHTML = m.join("");
27578 container.dom.insertBefore(el, position);
27580 this.el = Roo.get(el);
27581 this.eventEl = Roo.get(el.firstChild);
27583 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27584 handler: this.showPrevMonth,
27586 preventDefault:true,
27590 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27591 handler: this.showNextMonth,
27593 preventDefault:true,
27597 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27599 this.monthPicker = this.el.down('div.x-date-mp');
27600 this.monthPicker.enableDisplayMode('block');
27602 var kn = new Roo.KeyNav(this.eventEl, {
27603 "left" : function(e){
27605 this.showPrevMonth() :
27606 this.update(this.activeDate.add("d", -1));
27609 "right" : function(e){
27611 this.showNextMonth() :
27612 this.update(this.activeDate.add("d", 1));
27615 "up" : function(e){
27617 this.showNextYear() :
27618 this.update(this.activeDate.add("d", -7));
27621 "down" : function(e){
27623 this.showPrevYear() :
27624 this.update(this.activeDate.add("d", 7));
27627 "pageUp" : function(e){
27628 this.showNextMonth();
27631 "pageDown" : function(e){
27632 this.showPrevMonth();
27635 "enter" : function(e){
27636 e.stopPropagation();
27643 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27645 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27647 this.el.unselectable();
27649 this.cells = this.el.select("table.x-date-inner tbody td");
27650 this.textNodes = this.el.query("table.x-date-inner tbody span");
27652 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27654 tooltip: this.monthYearText
27657 this.mbtn.on('click', this.showMonthPicker, this);
27658 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27661 var today = (new Date()).dateFormat(this.format);
27663 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27664 if (this.showClear) {
27665 baseTb.add( new Roo.Toolbar.Fill());
27668 text: String.format(this.todayText, today),
27669 tooltip: String.format(this.todayTip, today),
27670 handler: this.selectToday,
27674 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27677 if (this.showClear) {
27679 baseTb.add( new Roo.Toolbar.Fill());
27682 cls: 'x-btn-icon x-btn-clear',
27683 handler: function() {
27685 this.fireEvent("select", this, '');
27695 this.update(this.value);
27698 createMonthPicker : function(){
27699 if(!this.monthPicker.dom.firstChild){
27700 var buf = ['<table border="0" cellspacing="0">'];
27701 for(var i = 0; i < 6; i++){
27703 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27704 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27706 '<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>' :
27707 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27711 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27713 '</button><button type="button" class="x-date-mp-cancel">',
27715 '</button></td></tr>',
27718 this.monthPicker.update(buf.join(''));
27719 this.monthPicker.on('click', this.onMonthClick, this);
27720 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27722 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27723 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27725 this.mpMonths.each(function(m, a, i){
27728 m.dom.xmonth = 5 + Math.round(i * .5);
27730 m.dom.xmonth = Math.round((i-1) * .5);
27736 showMonthPicker : function(){
27737 this.createMonthPicker();
27738 var size = this.el.getSize();
27739 this.monthPicker.setSize(size);
27740 this.monthPicker.child('table').setSize(size);
27742 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27743 this.updateMPMonth(this.mpSelMonth);
27744 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27745 this.updateMPYear(this.mpSelYear);
27747 this.monthPicker.slideIn('t', {duration:.2});
27750 updateMPYear : function(y){
27752 var ys = this.mpYears.elements;
27753 for(var i = 1; i <= 10; i++){
27754 var td = ys[i-1], y2;
27756 y2 = y + Math.round(i * .5);
27757 td.firstChild.innerHTML = y2;
27760 y2 = y - (5-Math.round(i * .5));
27761 td.firstChild.innerHTML = y2;
27764 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27768 updateMPMonth : function(sm){
27769 this.mpMonths.each(function(m, a, i){
27770 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27774 selectMPMonth: function(m){
27778 onMonthClick : function(e, t){
27780 var el = new Roo.Element(t), pn;
27781 if(el.is('button.x-date-mp-cancel')){
27782 this.hideMonthPicker();
27784 else if(el.is('button.x-date-mp-ok')){
27785 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27786 this.hideMonthPicker();
27788 else if(pn = el.up('td.x-date-mp-month', 2)){
27789 this.mpMonths.removeClass('x-date-mp-sel');
27790 pn.addClass('x-date-mp-sel');
27791 this.mpSelMonth = pn.dom.xmonth;
27793 else if(pn = el.up('td.x-date-mp-year', 2)){
27794 this.mpYears.removeClass('x-date-mp-sel');
27795 pn.addClass('x-date-mp-sel');
27796 this.mpSelYear = pn.dom.xyear;
27798 else if(el.is('a.x-date-mp-prev')){
27799 this.updateMPYear(this.mpyear-10);
27801 else if(el.is('a.x-date-mp-next')){
27802 this.updateMPYear(this.mpyear+10);
27806 onMonthDblClick : function(e, t){
27808 var el = new Roo.Element(t), pn;
27809 if(pn = el.up('td.x-date-mp-month', 2)){
27810 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27811 this.hideMonthPicker();
27813 else if(pn = el.up('td.x-date-mp-year', 2)){
27814 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27815 this.hideMonthPicker();
27819 hideMonthPicker : function(disableAnim){
27820 if(this.monthPicker){
27821 if(disableAnim === true){
27822 this.monthPicker.hide();
27824 this.monthPicker.slideOut('t', {duration:.2});
27830 showPrevMonth : function(e){
27831 this.update(this.activeDate.add("mo", -1));
27835 showNextMonth : function(e){
27836 this.update(this.activeDate.add("mo", 1));
27840 showPrevYear : function(){
27841 this.update(this.activeDate.add("y", -1));
27845 showNextYear : function(){
27846 this.update(this.activeDate.add("y", 1));
27850 handleMouseWheel : function(e){
27851 var delta = e.getWheelDelta();
27853 this.showPrevMonth();
27855 } else if(delta < 0){
27856 this.showNextMonth();
27862 handleDateClick : function(e, t){
27864 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
27865 this.setValue(new Date(t.dateValue));
27866 this.fireEvent("select", this, this.value);
27871 selectToday : function(){
27872 this.setValue(new Date().clearTime());
27873 this.fireEvent("select", this, this.value);
27877 update : function(date)
27879 var vd = this.activeDate;
27880 this.activeDate = date;
27882 var t = date.getTime();
27883 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
27884 this.cells.removeClass("x-date-selected");
27885 this.cells.each(function(c){
27886 if(c.dom.firstChild.dateValue == t){
27887 c.addClass("x-date-selected");
27888 setTimeout(function(){
27889 try{c.dom.firstChild.focus();}catch(e){}
27898 var days = date.getDaysInMonth();
27899 var firstOfMonth = date.getFirstDateOfMonth();
27900 var startingPos = firstOfMonth.getDay()-this.startDay;
27902 if(startingPos <= this.startDay){
27906 var pm = date.add("mo", -1);
27907 var prevStart = pm.getDaysInMonth()-startingPos;
27909 var cells = this.cells.elements;
27910 var textEls = this.textNodes;
27911 days += startingPos;
27913 // convert everything to numbers so it's fast
27914 var day = 86400000;
27915 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
27916 var today = new Date().clearTime().getTime();
27917 var sel = date.clearTime().getTime();
27918 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
27919 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
27920 var ddMatch = this.disabledDatesRE;
27921 var ddText = this.disabledDatesText;
27922 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
27923 var ddaysText = this.disabledDaysText;
27924 var format = this.format;
27926 var setCellClass = function(cal, cell){
27928 var t = d.getTime();
27929 cell.firstChild.dateValue = t;
27931 cell.className += " x-date-today";
27932 cell.title = cal.todayText;
27935 cell.className += " x-date-selected";
27936 setTimeout(function(){
27937 try{cell.firstChild.focus();}catch(e){}
27942 cell.className = " x-date-disabled";
27943 cell.title = cal.minText;
27947 cell.className = " x-date-disabled";
27948 cell.title = cal.maxText;
27952 if(ddays.indexOf(d.getDay()) != -1){
27953 cell.title = ddaysText;
27954 cell.className = " x-date-disabled";
27957 if(ddMatch && format){
27958 var fvalue = d.dateFormat(format);
27959 if(ddMatch.test(fvalue)){
27960 cell.title = ddText.replace("%0", fvalue);
27961 cell.className = " x-date-disabled";
27967 for(; i < startingPos; i++) {
27968 textEls[i].innerHTML = (++prevStart);
27969 d.setDate(d.getDate()+1);
27970 cells[i].className = "x-date-prevday";
27971 setCellClass(this, cells[i]);
27973 for(; i < days; i++){
27974 intDay = i - startingPos + 1;
27975 textEls[i].innerHTML = (intDay);
27976 d.setDate(d.getDate()+1);
27977 cells[i].className = "x-date-active";
27978 setCellClass(this, cells[i]);
27981 for(; i < 42; i++) {
27982 textEls[i].innerHTML = (++extraDays);
27983 d.setDate(d.getDate()+1);
27984 cells[i].className = "x-date-nextday";
27985 setCellClass(this, cells[i]);
27988 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
27989 this.fireEvent('monthchange', this, date);
27991 if(!this.internalRender){
27992 var main = this.el.dom.firstChild;
27993 var w = main.offsetWidth;
27994 this.el.setWidth(w + this.el.getBorderWidth("lr"));
27995 Roo.fly(main).setWidth(w);
27996 this.internalRender = true;
27997 // opera does not respect the auto grow header center column
27998 // then, after it gets a width opera refuses to recalculate
27999 // without a second pass
28000 if(Roo.isOpera && !this.secondPass){
28001 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28002 this.secondPass = true;
28003 this.update.defer(10, this, [date]);
28011 * Ext JS Library 1.1.1
28012 * Copyright(c) 2006-2007, Ext JS, LLC.
28014 * Originally Released Under LGPL - original licence link has changed is not relivant.
28017 * <script type="text/javascript">
28020 * @class Roo.TabPanel
28021 * @extends Roo.util.Observable
28022 * A lightweight tab container.
28026 // basic tabs 1, built from existing content
28027 var tabs = new Roo.TabPanel("tabs1");
28028 tabs.addTab("script", "View Script");
28029 tabs.addTab("markup", "View Markup");
28030 tabs.activate("script");
28032 // more advanced tabs, built from javascript
28033 var jtabs = new Roo.TabPanel("jtabs");
28034 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28036 // set up the UpdateManager
28037 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28038 var updater = tab2.getUpdateManager();
28039 updater.setDefaultUrl("ajax1.htm");
28040 tab2.on('activate', updater.refresh, updater, true);
28042 // Use setUrl for Ajax loading
28043 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28044 tab3.setUrl("ajax2.htm", null, true);
28047 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28050 jtabs.activate("jtabs-1");
28053 * Create a new TabPanel.
28054 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28055 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28057 Roo.TabPanel = function(container, config){
28059 * The container element for this TabPanel.
28060 * @type Roo.Element
28062 this.el = Roo.get(container, true);
28064 if(typeof config == "boolean"){
28065 this.tabPosition = config ? "bottom" : "top";
28067 Roo.apply(this, config);
28070 if(this.tabPosition == "bottom"){
28071 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28072 this.el.addClass("x-tabs-bottom");
28074 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28075 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28076 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28078 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28080 if(this.tabPosition != "bottom"){
28081 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28082 * @type Roo.Element
28084 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28085 this.el.addClass("x-tabs-top");
28089 this.bodyEl.setStyle("position", "relative");
28091 this.active = null;
28092 this.activateDelegate = this.activate.createDelegate(this);
28097 * Fires when the active tab changes
28098 * @param {Roo.TabPanel} this
28099 * @param {Roo.TabPanelItem} activePanel The new active tab
28103 * @event beforetabchange
28104 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28105 * @param {Roo.TabPanel} this
28106 * @param {Object} e Set cancel to true on this object to cancel the tab change
28107 * @param {Roo.TabPanelItem} tab The tab being changed to
28109 "beforetabchange" : true
28112 Roo.EventManager.onWindowResize(this.onResize, this);
28113 this.cpad = this.el.getPadding("lr");
28114 this.hiddenCount = 0;
28117 // toolbar on the tabbar support...
28118 if (this.toolbar) {
28119 var tcfg = this.toolbar;
28120 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28121 this.toolbar = new Roo.Toolbar(tcfg);
28122 if (Roo.isSafari) {
28123 var tbl = tcfg.container.child('table', true);
28124 tbl.setAttribute('width', '100%');
28131 Roo.TabPanel.superclass.constructor.call(this);
28134 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28136 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28138 tabPosition : "top",
28140 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28142 currentTabWidth : 0,
28144 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28148 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28152 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28154 preferredTabWidth : 175,
28156 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28158 resizeTabs : false,
28160 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28162 monitorResize : true,
28164 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28169 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28170 * @param {String} id The id of the div to use <b>or create</b>
28171 * @param {String} text The text for the tab
28172 * @param {String} content (optional) Content to put in the TabPanelItem body
28173 * @param {Boolean} closable (optional) True to create a close icon on the tab
28174 * @return {Roo.TabPanelItem} The created TabPanelItem
28176 addTab : function(id, text, content, closable){
28177 var item = new Roo.TabPanelItem(this, id, text, closable);
28178 this.addTabItem(item);
28180 item.setContent(content);
28186 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28187 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28188 * @return {Roo.TabPanelItem}
28190 getTab : function(id){
28191 return this.items[id];
28195 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28196 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28198 hideTab : function(id){
28199 var t = this.items[id];
28202 this.hiddenCount++;
28203 this.autoSizeTabs();
28208 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28209 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28211 unhideTab : function(id){
28212 var t = this.items[id];
28214 t.setHidden(false);
28215 this.hiddenCount--;
28216 this.autoSizeTabs();
28221 * Adds an existing {@link Roo.TabPanelItem}.
28222 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28224 addTabItem : function(item){
28225 this.items[item.id] = item;
28226 this.items.push(item);
28227 if(this.resizeTabs){
28228 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28229 this.autoSizeTabs();
28236 * Removes a {@link Roo.TabPanelItem}.
28237 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28239 removeTab : function(id){
28240 var items = this.items;
28241 var tab = items[id];
28242 if(!tab) { return; }
28243 var index = items.indexOf(tab);
28244 if(this.active == tab && items.length > 1){
28245 var newTab = this.getNextAvailable(index);
28250 this.stripEl.dom.removeChild(tab.pnode.dom);
28251 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28252 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28254 items.splice(index, 1);
28255 delete this.items[tab.id];
28256 tab.fireEvent("close", tab);
28257 tab.purgeListeners();
28258 this.autoSizeTabs();
28261 getNextAvailable : function(start){
28262 var items = this.items;
28264 // look for a next tab that will slide over to
28265 // replace the one being removed
28266 while(index < items.length){
28267 var item = items[++index];
28268 if(item && !item.isHidden()){
28272 // if one isn't found select the previous tab (on the left)
28275 var item = items[--index];
28276 if(item && !item.isHidden()){
28284 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28285 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28287 disableTab : function(id){
28288 var tab = this.items[id];
28289 if(tab && this.active != tab){
28295 * Enables a {@link Roo.TabPanelItem} that is disabled.
28296 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28298 enableTab : function(id){
28299 var tab = this.items[id];
28304 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28305 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28306 * @return {Roo.TabPanelItem} The TabPanelItem.
28308 activate : function(id){
28309 var tab = this.items[id];
28313 if(tab == this.active || tab.disabled){
28317 this.fireEvent("beforetabchange", this, e, tab);
28318 if(e.cancel !== true && !tab.disabled){
28320 this.active.hide();
28322 this.active = this.items[id];
28323 this.active.show();
28324 this.fireEvent("tabchange", this, this.active);
28330 * Gets the active {@link Roo.TabPanelItem}.
28331 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28333 getActiveTab : function(){
28334 return this.active;
28338 * Updates the tab body element to fit the height of the container element
28339 * for overflow scrolling
28340 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28342 syncHeight : function(targetHeight){
28343 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28344 var bm = this.bodyEl.getMargins();
28345 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28346 this.bodyEl.setHeight(newHeight);
28350 onResize : function(){
28351 if(this.monitorResize){
28352 this.autoSizeTabs();
28357 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28359 beginUpdate : function(){
28360 this.updating = true;
28364 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28366 endUpdate : function(){
28367 this.updating = false;
28368 this.autoSizeTabs();
28372 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28374 autoSizeTabs : function(){
28375 var count = this.items.length;
28376 var vcount = count - this.hiddenCount;
28377 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28380 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28381 var availWidth = Math.floor(w / vcount);
28382 var b = this.stripBody;
28383 if(b.getWidth() > w){
28384 var tabs = this.items;
28385 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28386 if(availWidth < this.minTabWidth){
28387 /*if(!this.sleft){ // incomplete scrolling code
28388 this.createScrollButtons();
28391 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28394 if(this.currentTabWidth < this.preferredTabWidth){
28395 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28401 * Returns the number of tabs in this TabPanel.
28404 getCount : function(){
28405 return this.items.length;
28409 * Resizes all the tabs to the passed width
28410 * @param {Number} The new width
28412 setTabWidth : function(width){
28413 this.currentTabWidth = width;
28414 for(var i = 0, len = this.items.length; i < len; i++) {
28415 if(!this.items[i].isHidden()) {
28416 this.items[i].setWidth(width);
28422 * Destroys this TabPanel
28423 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28425 destroy : function(removeEl){
28426 Roo.EventManager.removeResizeListener(this.onResize, this);
28427 for(var i = 0, len = this.items.length; i < len; i++){
28428 this.items[i].purgeListeners();
28430 if(removeEl === true){
28431 this.el.update("");
28438 * @class Roo.TabPanelItem
28439 * @extends Roo.util.Observable
28440 * Represents an individual item (tab plus body) in a TabPanel.
28441 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28442 * @param {String} id The id of this TabPanelItem
28443 * @param {String} text The text for the tab of this TabPanelItem
28444 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28446 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28448 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28449 * @type Roo.TabPanel
28451 this.tabPanel = tabPanel;
28453 * The id for this TabPanelItem
28458 this.disabled = false;
28462 this.loaded = false;
28463 this.closable = closable;
28466 * The body element for this TabPanelItem.
28467 * @type Roo.Element
28469 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28470 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28471 this.bodyEl.setStyle("display", "block");
28472 this.bodyEl.setStyle("zoom", "1");
28475 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28477 this.el = Roo.get(els.el, true);
28478 this.inner = Roo.get(els.inner, true);
28479 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28480 this.pnode = Roo.get(els.el.parentNode, true);
28481 this.el.on("mousedown", this.onTabMouseDown, this);
28482 this.el.on("click", this.onTabClick, this);
28485 var c = Roo.get(els.close, true);
28486 c.dom.title = this.closeText;
28487 c.addClassOnOver("close-over");
28488 c.on("click", this.closeClick, this);
28494 * Fires when this tab becomes the active tab.
28495 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28496 * @param {Roo.TabPanelItem} this
28500 * @event beforeclose
28501 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28502 * @param {Roo.TabPanelItem} this
28503 * @param {Object} e Set cancel to true on this object to cancel the close.
28505 "beforeclose": true,
28508 * Fires when this tab is closed.
28509 * @param {Roo.TabPanelItem} this
28513 * @event deactivate
28514 * Fires when this tab is no longer the active tab.
28515 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28516 * @param {Roo.TabPanelItem} this
28518 "deactivate" : true
28520 this.hidden = false;
28522 Roo.TabPanelItem.superclass.constructor.call(this);
28525 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28526 purgeListeners : function(){
28527 Roo.util.Observable.prototype.purgeListeners.call(this);
28528 this.el.removeAllListeners();
28531 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28534 this.pnode.addClass("on");
28537 this.tabPanel.stripWrap.repaint();
28539 this.fireEvent("activate", this.tabPanel, this);
28543 * Returns true if this tab is the active tab.
28544 * @return {Boolean}
28546 isActive : function(){
28547 return this.tabPanel.getActiveTab() == this;
28551 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28554 this.pnode.removeClass("on");
28556 this.fireEvent("deactivate", this.tabPanel, this);
28559 hideAction : function(){
28560 this.bodyEl.hide();
28561 this.bodyEl.setStyle("position", "absolute");
28562 this.bodyEl.setLeft("-20000px");
28563 this.bodyEl.setTop("-20000px");
28566 showAction : function(){
28567 this.bodyEl.setStyle("position", "relative");
28568 this.bodyEl.setTop("");
28569 this.bodyEl.setLeft("");
28570 this.bodyEl.show();
28574 * Set the tooltip for the tab.
28575 * @param {String} tooltip The tab's tooltip
28577 setTooltip : function(text){
28578 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28579 this.textEl.dom.qtip = text;
28580 this.textEl.dom.removeAttribute('title');
28582 this.textEl.dom.title = text;
28586 onTabClick : function(e){
28587 e.preventDefault();
28588 this.tabPanel.activate(this.id);
28591 onTabMouseDown : function(e){
28592 e.preventDefault();
28593 this.tabPanel.activate(this.id);
28596 getWidth : function(){
28597 return this.inner.getWidth();
28600 setWidth : function(width){
28601 var iwidth = width - this.pnode.getPadding("lr");
28602 this.inner.setWidth(iwidth);
28603 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28604 this.pnode.setWidth(width);
28608 * Show or hide the tab
28609 * @param {Boolean} hidden True to hide or false to show.
28611 setHidden : function(hidden){
28612 this.hidden = hidden;
28613 this.pnode.setStyle("display", hidden ? "none" : "");
28617 * Returns true if this tab is "hidden"
28618 * @return {Boolean}
28620 isHidden : function(){
28621 return this.hidden;
28625 * Returns the text for this tab
28628 getText : function(){
28632 autoSize : function(){
28633 //this.el.beginMeasure();
28634 this.textEl.setWidth(1);
28636 * #2804 [new] Tabs in Roojs
28637 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28639 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28640 //this.el.endMeasure();
28644 * Sets the text for the tab (Note: this also sets the tooltip text)
28645 * @param {String} text The tab's text and tooltip
28647 setText : function(text){
28649 this.textEl.update(text);
28650 this.setTooltip(text);
28651 if(!this.tabPanel.resizeTabs){
28656 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28658 activate : function(){
28659 this.tabPanel.activate(this.id);
28663 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28665 disable : function(){
28666 if(this.tabPanel.active != this){
28667 this.disabled = true;
28668 this.pnode.addClass("disabled");
28673 * Enables this TabPanelItem if it was previously disabled.
28675 enable : function(){
28676 this.disabled = false;
28677 this.pnode.removeClass("disabled");
28681 * Sets the content for this TabPanelItem.
28682 * @param {String} content The content
28683 * @param {Boolean} loadScripts true to look for and load scripts
28685 setContent : function(content, loadScripts){
28686 this.bodyEl.update(content, loadScripts);
28690 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28691 * @return {Roo.UpdateManager} The UpdateManager
28693 getUpdateManager : function(){
28694 return this.bodyEl.getUpdateManager();
28698 * Set a URL to be used to load the content for this TabPanelItem.
28699 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28700 * @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)
28701 * @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)
28702 * @return {Roo.UpdateManager} The UpdateManager
28704 setUrl : function(url, params, loadOnce){
28705 if(this.refreshDelegate){
28706 this.un('activate', this.refreshDelegate);
28708 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28709 this.on("activate", this.refreshDelegate);
28710 return this.bodyEl.getUpdateManager();
28714 _handleRefresh : function(url, params, loadOnce){
28715 if(!loadOnce || !this.loaded){
28716 var updater = this.bodyEl.getUpdateManager();
28717 updater.update(url, params, this._setLoaded.createDelegate(this));
28722 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28723 * Will fail silently if the setUrl method has not been called.
28724 * This does not activate the panel, just updates its content.
28726 refresh : function(){
28727 if(this.refreshDelegate){
28728 this.loaded = false;
28729 this.refreshDelegate();
28734 _setLoaded : function(){
28735 this.loaded = true;
28739 closeClick : function(e){
28742 this.fireEvent("beforeclose", this, o);
28743 if(o.cancel !== true){
28744 this.tabPanel.removeTab(this.id);
28748 * The text displayed in the tooltip for the close icon.
28751 closeText : "Close this tab"
28755 Roo.TabPanel.prototype.createStrip = function(container){
28756 var strip = document.createElement("div");
28757 strip.className = "x-tabs-wrap";
28758 container.appendChild(strip);
28762 Roo.TabPanel.prototype.createStripList = function(strip){
28763 // div wrapper for retard IE
28764 // returns the "tr" element.
28765 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28766 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28767 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28768 return strip.firstChild.firstChild.firstChild.firstChild;
28771 Roo.TabPanel.prototype.createBody = function(container){
28772 var body = document.createElement("div");
28773 Roo.id(body, "tab-body");
28774 Roo.fly(body).addClass("x-tabs-body");
28775 container.appendChild(body);
28779 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28780 var body = Roo.getDom(id);
28782 body = document.createElement("div");
28785 Roo.fly(body).addClass("x-tabs-item-body");
28786 bodyEl.insertBefore(body, bodyEl.firstChild);
28790 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28791 var td = document.createElement("td");
28792 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28793 //stripEl.appendChild(td);
28795 td.className = "x-tabs-closable";
28796 if(!this.closeTpl){
28797 this.closeTpl = new Roo.Template(
28798 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28799 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28800 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28803 var el = this.closeTpl.overwrite(td, {"text": text});
28804 var close = el.getElementsByTagName("div")[0];
28805 var inner = el.getElementsByTagName("em")[0];
28806 return {"el": el, "close": close, "inner": inner};
28809 this.tabTpl = new Roo.Template(
28810 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28811 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28814 var el = this.tabTpl.overwrite(td, {"text": text});
28815 var inner = el.getElementsByTagName("em")[0];
28816 return {"el": el, "inner": inner};
28820 * Ext JS Library 1.1.1
28821 * Copyright(c) 2006-2007, Ext JS, LLC.
28823 * Originally Released Under LGPL - original licence link has changed is not relivant.
28826 * <script type="text/javascript">
28830 * @class Roo.Button
28831 * @extends Roo.util.Observable
28832 * Simple Button class
28833 * @cfg {String} text The button text
28834 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28835 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28836 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28837 * @cfg {Object} scope The scope of the handler
28838 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28839 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28840 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28841 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28842 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28843 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28844 applies if enableToggle = true)
28845 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28846 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28847 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28849 * Create a new button
28850 * @param {Object} config The config object
28852 Roo.Button = function(renderTo, config)
28856 renderTo = config.renderTo || false;
28859 Roo.apply(this, config);
28863 * Fires when this button is clicked
28864 * @param {Button} this
28865 * @param {EventObject} e The click event
28870 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
28871 * @param {Button} this
28872 * @param {Boolean} pressed
28877 * Fires when the mouse hovers over the button
28878 * @param {Button} this
28879 * @param {Event} e The event object
28881 'mouseover' : true,
28884 * Fires when the mouse exits the button
28885 * @param {Button} this
28886 * @param {Event} e The event object
28891 * Fires when the button is rendered
28892 * @param {Button} this
28897 this.menu = Roo.menu.MenuMgr.get(this.menu);
28899 // register listeners first!! - so render can be captured..
28900 Roo.util.Observable.call(this);
28902 this.render(renderTo);
28908 Roo.extend(Roo.Button, Roo.util.Observable, {
28914 * Read-only. True if this button is hidden
28919 * Read-only. True if this button is disabled
28924 * Read-only. True if this button is pressed (only if enableToggle = true)
28930 * @cfg {Number} tabIndex
28931 * The DOM tabIndex for this button (defaults to undefined)
28933 tabIndex : undefined,
28936 * @cfg {Boolean} enableToggle
28937 * True to enable pressed/not pressed toggling (defaults to false)
28939 enableToggle: false,
28941 * @cfg {Mixed} menu
28942 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
28946 * @cfg {String} menuAlign
28947 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
28949 menuAlign : "tl-bl?",
28952 * @cfg {String} iconCls
28953 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
28955 iconCls : undefined,
28957 * @cfg {String} type
28958 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
28963 menuClassTarget: 'tr',
28966 * @cfg {String} clickEvent
28967 * The type of event to map to the button's event handler (defaults to 'click')
28969 clickEvent : 'click',
28972 * @cfg {Boolean} handleMouseEvents
28973 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
28975 handleMouseEvents : true,
28978 * @cfg {String} tooltipType
28979 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
28981 tooltipType : 'qtip',
28984 * @cfg {String} cls
28985 * A CSS class to apply to the button's main element.
28989 * @cfg {Roo.Template} template (Optional)
28990 * An {@link Roo.Template} with which to create the Button's main element. This Template must
28991 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
28992 * require code modifications if required elements (e.g. a button) aren't present.
28996 render : function(renderTo){
28998 if(this.hideParent){
28999 this.parentEl = Roo.get(renderTo);
29001 if(!this.dhconfig){
29002 if(!this.template){
29003 if(!Roo.Button.buttonTemplate){
29004 // hideous table template
29005 Roo.Button.buttonTemplate = new Roo.Template(
29006 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29007 '<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>',
29008 "</tr></tbody></table>");
29010 this.template = Roo.Button.buttonTemplate;
29012 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29013 var btnEl = btn.child("button:first");
29014 btnEl.on('focus', this.onFocus, this);
29015 btnEl.on('blur', this.onBlur, this);
29017 btn.addClass(this.cls);
29020 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29023 btnEl.addClass(this.iconCls);
29025 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29028 if(this.tabIndex !== undefined){
29029 btnEl.dom.tabIndex = this.tabIndex;
29032 if(typeof this.tooltip == 'object'){
29033 Roo.QuickTips.tips(Roo.apply({
29037 btnEl.dom[this.tooltipType] = this.tooltip;
29041 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29045 this.el.dom.id = this.el.id = this.id;
29048 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29049 this.menu.on("show", this.onMenuShow, this);
29050 this.menu.on("hide", this.onMenuHide, this);
29052 btn.addClass("x-btn");
29053 if(Roo.isIE && !Roo.isIE7){
29054 this.autoWidth.defer(1, this);
29058 if(this.handleMouseEvents){
29059 btn.on("mouseover", this.onMouseOver, this);
29060 btn.on("mouseout", this.onMouseOut, this);
29061 btn.on("mousedown", this.onMouseDown, this);
29063 btn.on(this.clickEvent, this.onClick, this);
29064 //btn.on("mouseup", this.onMouseUp, this);
29071 Roo.ButtonToggleMgr.register(this);
29073 this.el.addClass("x-btn-pressed");
29076 var repeater = new Roo.util.ClickRepeater(btn,
29077 typeof this.repeat == "object" ? this.repeat : {}
29079 repeater.on("click", this.onClick, this);
29082 this.fireEvent('render', this);
29086 * Returns the button's underlying element
29087 * @return {Roo.Element} The element
29089 getEl : function(){
29094 * Destroys this Button and removes any listeners.
29096 destroy : function(){
29097 Roo.ButtonToggleMgr.unregister(this);
29098 this.el.removeAllListeners();
29099 this.purgeListeners();
29104 autoWidth : function(){
29106 this.el.setWidth("auto");
29107 if(Roo.isIE7 && Roo.isStrict){
29108 var ib = this.el.child('button');
29109 if(ib && ib.getWidth() > 20){
29111 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29116 this.el.beginMeasure();
29118 if(this.el.getWidth() < this.minWidth){
29119 this.el.setWidth(this.minWidth);
29122 this.el.endMeasure();
29129 * Assigns this button's click handler
29130 * @param {Function} handler The function to call when the button is clicked
29131 * @param {Object} scope (optional) Scope for the function passed in
29133 setHandler : function(handler, scope){
29134 this.handler = handler;
29135 this.scope = scope;
29139 * Sets this button's text
29140 * @param {String} text The button text
29142 setText : function(text){
29145 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29151 * Gets the text for this button
29152 * @return {String} The button text
29154 getText : function(){
29162 this.hidden = false;
29164 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29172 this.hidden = true;
29174 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29179 * Convenience function for boolean show/hide
29180 * @param {Boolean} visible True to show, false to hide
29182 setVisible: function(visible){
29191 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29192 * @param {Boolean} state (optional) Force a particular state
29194 toggle : function(state){
29195 state = state === undefined ? !this.pressed : state;
29196 if(state != this.pressed){
29198 this.el.addClass("x-btn-pressed");
29199 this.pressed = true;
29200 this.fireEvent("toggle", this, true);
29202 this.el.removeClass("x-btn-pressed");
29203 this.pressed = false;
29204 this.fireEvent("toggle", this, false);
29206 if(this.toggleHandler){
29207 this.toggleHandler.call(this.scope || this, this, state);
29215 focus : function(){
29216 this.el.child('button:first').focus();
29220 * Disable this button
29222 disable : function(){
29224 this.el.addClass("x-btn-disabled");
29226 this.disabled = true;
29230 * Enable this button
29232 enable : function(){
29234 this.el.removeClass("x-btn-disabled");
29236 this.disabled = false;
29240 * Convenience function for boolean enable/disable
29241 * @param {Boolean} enabled True to enable, false to disable
29243 setDisabled : function(v){
29244 this[v !== true ? "enable" : "disable"]();
29248 onClick : function(e)
29251 e.preventDefault();
29256 if(!this.disabled){
29257 if(this.enableToggle){
29260 if(this.menu && !this.menu.isVisible()){
29261 this.menu.show(this.el, this.menuAlign);
29263 this.fireEvent("click", this, e);
29265 this.el.removeClass("x-btn-over");
29266 this.handler.call(this.scope || this, this, e);
29271 onMouseOver : function(e){
29272 if(!this.disabled){
29273 this.el.addClass("x-btn-over");
29274 this.fireEvent('mouseover', this, e);
29278 onMouseOut : function(e){
29279 if(!e.within(this.el, true)){
29280 this.el.removeClass("x-btn-over");
29281 this.fireEvent('mouseout', this, e);
29285 onFocus : function(e){
29286 if(!this.disabled){
29287 this.el.addClass("x-btn-focus");
29291 onBlur : function(e){
29292 this.el.removeClass("x-btn-focus");
29295 onMouseDown : function(e){
29296 if(!this.disabled && e.button == 0){
29297 this.el.addClass("x-btn-click");
29298 Roo.get(document).on('mouseup', this.onMouseUp, this);
29302 onMouseUp : function(e){
29304 this.el.removeClass("x-btn-click");
29305 Roo.get(document).un('mouseup', this.onMouseUp, this);
29309 onMenuShow : function(e){
29310 this.el.addClass("x-btn-menu-active");
29313 onMenuHide : function(e){
29314 this.el.removeClass("x-btn-menu-active");
29318 // Private utility class used by Button
29319 Roo.ButtonToggleMgr = function(){
29322 function toggleGroup(btn, state){
29324 var g = groups[btn.toggleGroup];
29325 for(var i = 0, l = g.length; i < l; i++){
29327 g[i].toggle(false);
29334 register : function(btn){
29335 if(!btn.toggleGroup){
29338 var g = groups[btn.toggleGroup];
29340 g = groups[btn.toggleGroup] = [];
29343 btn.on("toggle", toggleGroup);
29346 unregister : function(btn){
29347 if(!btn.toggleGroup){
29350 var g = groups[btn.toggleGroup];
29353 btn.un("toggle", toggleGroup);
29359 * Ext JS Library 1.1.1
29360 * Copyright(c) 2006-2007, Ext JS, LLC.
29362 * Originally Released Under LGPL - original licence link has changed is not relivant.
29365 * <script type="text/javascript">
29369 * @class Roo.SplitButton
29370 * @extends Roo.Button
29371 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29372 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29373 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29374 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29375 * @cfg {String} arrowTooltip The title attribute of the arrow
29377 * Create a new menu button
29378 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29379 * @param {Object} config The config object
29381 Roo.SplitButton = function(renderTo, config){
29382 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29384 * @event arrowclick
29385 * Fires when this button's arrow is clicked
29386 * @param {SplitButton} this
29387 * @param {EventObject} e The click event
29389 this.addEvents({"arrowclick":true});
29392 Roo.extend(Roo.SplitButton, Roo.Button, {
29393 render : function(renderTo){
29394 // this is one sweet looking template!
29395 var tpl = new Roo.Template(
29396 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29397 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29398 '<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>',
29399 "</tbody></table></td><td>",
29400 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29401 '<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>',
29402 "</tbody></table></td></tr></table>"
29404 var btn = tpl.append(renderTo, [this.text, this.type], true);
29405 var btnEl = btn.child("button");
29407 btn.addClass(this.cls);
29410 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29413 btnEl.addClass(this.iconCls);
29415 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29419 if(this.handleMouseEvents){
29420 btn.on("mouseover", this.onMouseOver, this);
29421 btn.on("mouseout", this.onMouseOut, this);
29422 btn.on("mousedown", this.onMouseDown, this);
29423 btn.on("mouseup", this.onMouseUp, this);
29425 btn.on(this.clickEvent, this.onClick, this);
29427 if(typeof this.tooltip == 'object'){
29428 Roo.QuickTips.tips(Roo.apply({
29432 btnEl.dom[this.tooltipType] = this.tooltip;
29435 if(this.arrowTooltip){
29436 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29445 this.el.addClass("x-btn-pressed");
29447 if(Roo.isIE && !Roo.isIE7){
29448 this.autoWidth.defer(1, this);
29453 this.menu.on("show", this.onMenuShow, this);
29454 this.menu.on("hide", this.onMenuHide, this);
29456 this.fireEvent('render', this);
29460 autoWidth : function(){
29462 var tbl = this.el.child("table:first");
29463 var tbl2 = this.el.child("table:last");
29464 this.el.setWidth("auto");
29465 tbl.setWidth("auto");
29466 if(Roo.isIE7 && Roo.isStrict){
29467 var ib = this.el.child('button:first');
29468 if(ib && ib.getWidth() > 20){
29470 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29475 this.el.beginMeasure();
29477 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29478 tbl.setWidth(this.minWidth-tbl2.getWidth());
29481 this.el.endMeasure();
29484 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29488 * Sets this button's click handler
29489 * @param {Function} handler The function to call when the button is clicked
29490 * @param {Object} scope (optional) Scope for the function passed above
29492 setHandler : function(handler, scope){
29493 this.handler = handler;
29494 this.scope = scope;
29498 * Sets this button's arrow click handler
29499 * @param {Function} handler The function to call when the arrow is clicked
29500 * @param {Object} scope (optional) Scope for the function passed above
29502 setArrowHandler : function(handler, scope){
29503 this.arrowHandler = handler;
29504 this.scope = scope;
29510 focus : function(){
29512 this.el.child("button:first").focus();
29517 onClick : function(e){
29518 e.preventDefault();
29519 if(!this.disabled){
29520 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29521 if(this.menu && !this.menu.isVisible()){
29522 this.menu.show(this.el, this.menuAlign);
29524 this.fireEvent("arrowclick", this, e);
29525 if(this.arrowHandler){
29526 this.arrowHandler.call(this.scope || this, this, e);
29529 this.fireEvent("click", this, e);
29531 this.handler.call(this.scope || this, this, e);
29537 onMouseDown : function(e){
29538 if(!this.disabled){
29539 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29543 onMouseUp : function(e){
29544 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29549 // backwards compat
29550 Roo.MenuButton = Roo.SplitButton;/*
29552 * Ext JS Library 1.1.1
29553 * Copyright(c) 2006-2007, Ext JS, LLC.
29555 * Originally Released Under LGPL - original licence link has changed is not relivant.
29558 * <script type="text/javascript">
29562 * @class Roo.Toolbar
29563 * Basic Toolbar class.
29565 * Creates a new Toolbar
29566 * @param {Object} container The config object
29568 Roo.Toolbar = function(container, buttons, config)
29570 /// old consturctor format still supported..
29571 if(container instanceof Array){ // omit the container for later rendering
29572 buttons = container;
29576 if (typeof(container) == 'object' && container.xtype) {
29577 config = container;
29578 container = config.container;
29579 buttons = config.buttons || []; // not really - use items!!
29582 if (config && config.items) {
29583 xitems = config.items;
29584 delete config.items;
29586 Roo.apply(this, config);
29587 this.buttons = buttons;
29590 this.render(container);
29592 this.xitems = xitems;
29593 Roo.each(xitems, function(b) {
29599 Roo.Toolbar.prototype = {
29601 * @cfg {Array} items
29602 * array of button configs or elements to add (will be converted to a MixedCollection)
29606 * @cfg {String/HTMLElement/Element} container
29607 * The id or element that will contain the toolbar
29610 render : function(ct){
29611 this.el = Roo.get(ct);
29613 this.el.addClass(this.cls);
29615 // using a table allows for vertical alignment
29616 // 100% width is needed by Safari...
29617 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29618 this.tr = this.el.child("tr", true);
29620 this.items = new Roo.util.MixedCollection(false, function(o){
29621 return o.id || ("item" + (++autoId));
29624 this.add.apply(this, this.buttons);
29625 delete this.buttons;
29630 * Adds element(s) to the toolbar -- this function takes a variable number of
29631 * arguments of mixed type and adds them to the toolbar.
29632 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29634 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29635 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29636 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29637 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29638 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29639 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29640 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29641 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29642 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29644 * @param {Mixed} arg2
29645 * @param {Mixed} etc.
29648 var a = arguments, l = a.length;
29649 for(var i = 0; i < l; i++){
29654 _add : function(el) {
29657 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29660 if (el.applyTo){ // some kind of form field
29661 return this.addField(el);
29663 if (el.render){ // some kind of Toolbar.Item
29664 return this.addItem(el);
29666 if (typeof el == "string"){ // string
29667 if(el == "separator" || el == "-"){
29668 return this.addSeparator();
29671 return this.addSpacer();
29674 return this.addFill();
29676 return this.addText(el);
29679 if(el.tagName){ // element
29680 return this.addElement(el);
29682 if(typeof el == "object"){ // must be button config?
29683 return this.addButton(el);
29685 // and now what?!?!
29691 * Add an Xtype element
29692 * @param {Object} xtype Xtype Object
29693 * @return {Object} created Object
29695 addxtype : function(e){
29696 return this.add(e);
29700 * Returns the Element for this toolbar.
29701 * @return {Roo.Element}
29703 getEl : function(){
29709 * @return {Roo.Toolbar.Item} The separator item
29711 addSeparator : function(){
29712 return this.addItem(new Roo.Toolbar.Separator());
29716 * Adds a spacer element
29717 * @return {Roo.Toolbar.Spacer} The spacer item
29719 addSpacer : function(){
29720 return this.addItem(new Roo.Toolbar.Spacer());
29724 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29725 * @return {Roo.Toolbar.Fill} The fill item
29727 addFill : function(){
29728 return this.addItem(new Roo.Toolbar.Fill());
29732 * Adds any standard HTML element to the toolbar
29733 * @param {String/HTMLElement/Element} el The element or id of the element to add
29734 * @return {Roo.Toolbar.Item} The element's item
29736 addElement : function(el){
29737 return this.addItem(new Roo.Toolbar.Item(el));
29740 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29741 * @type Roo.util.MixedCollection
29746 * Adds any Toolbar.Item or subclass
29747 * @param {Roo.Toolbar.Item} item
29748 * @return {Roo.Toolbar.Item} The item
29750 addItem : function(item){
29751 var td = this.nextBlock();
29753 this.items.add(item);
29758 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29759 * @param {Object/Array} config A button config or array of configs
29760 * @return {Roo.Toolbar.Button/Array}
29762 addButton : function(config){
29763 if(config instanceof Array){
29765 for(var i = 0, len = config.length; i < len; i++) {
29766 buttons.push(this.addButton(config[i]));
29771 if(!(config instanceof Roo.Toolbar.Button)){
29773 new Roo.Toolbar.SplitButton(config) :
29774 new Roo.Toolbar.Button(config);
29776 var td = this.nextBlock();
29783 * Adds text to the toolbar
29784 * @param {String} text The text to add
29785 * @return {Roo.Toolbar.Item} The element's item
29787 addText : function(text){
29788 return this.addItem(new Roo.Toolbar.TextItem(text));
29792 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29793 * @param {Number} index The index where the item is to be inserted
29794 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29795 * @return {Roo.Toolbar.Button/Item}
29797 insertButton : function(index, item){
29798 if(item instanceof Array){
29800 for(var i = 0, len = item.length; i < len; i++) {
29801 buttons.push(this.insertButton(index + i, item[i]));
29805 if (!(item instanceof Roo.Toolbar.Button)){
29806 item = new Roo.Toolbar.Button(item);
29808 var td = document.createElement("td");
29809 this.tr.insertBefore(td, this.tr.childNodes[index]);
29811 this.items.insert(index, item);
29816 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29817 * @param {Object} config
29818 * @return {Roo.Toolbar.Item} The element's item
29820 addDom : function(config, returnEl){
29821 var td = this.nextBlock();
29822 Roo.DomHelper.overwrite(td, config);
29823 var ti = new Roo.Toolbar.Item(td.firstChild);
29825 this.items.add(ti);
29830 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29831 * @type Roo.util.MixedCollection
29836 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29837 * Note: the field should not have been rendered yet. For a field that has already been
29838 * rendered, use {@link #addElement}.
29839 * @param {Roo.form.Field} field
29840 * @return {Roo.ToolbarItem}
29844 addField : function(field) {
29845 if (!this.fields) {
29847 this.fields = new Roo.util.MixedCollection(false, function(o){
29848 return o.id || ("item" + (++autoId));
29853 var td = this.nextBlock();
29855 var ti = new Roo.Toolbar.Item(td.firstChild);
29857 this.items.add(ti);
29858 this.fields.add(field);
29869 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
29870 this.el.child('div').hide();
29878 this.el.child('div').show();
29882 nextBlock : function(){
29883 var td = document.createElement("td");
29884 this.tr.appendChild(td);
29889 destroy : function(){
29890 if(this.items){ // rendered?
29891 Roo.destroy.apply(Roo, this.items.items);
29893 if(this.fields){ // rendered?
29894 Roo.destroy.apply(Roo, this.fields.items);
29896 Roo.Element.uncache(this.el, this.tr);
29901 * @class Roo.Toolbar.Item
29902 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
29904 * Creates a new Item
29905 * @param {HTMLElement} el
29907 Roo.Toolbar.Item = function(el){
29909 if (typeof (el.xtype) != 'undefined') {
29914 this.el = Roo.getDom(el);
29915 this.id = Roo.id(this.el);
29916 this.hidden = false;
29921 * Fires when the button is rendered
29922 * @param {Button} this
29926 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
29928 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
29929 //Roo.Toolbar.Item.prototype = {
29932 * Get this item's HTML Element
29933 * @return {HTMLElement}
29935 getEl : function(){
29940 render : function(td){
29943 td.appendChild(this.el);
29945 this.fireEvent('render', this);
29949 * Removes and destroys this item.
29951 destroy : function(){
29952 this.td.parentNode.removeChild(this.td);
29959 this.hidden = false;
29960 this.td.style.display = "";
29967 this.hidden = true;
29968 this.td.style.display = "none";
29972 * Convenience function for boolean show/hide.
29973 * @param {Boolean} visible true to show/false to hide
29975 setVisible: function(visible){
29984 * Try to focus this item.
29986 focus : function(){
29987 Roo.fly(this.el).focus();
29991 * Disables this item.
29993 disable : function(){
29994 Roo.fly(this.td).addClass("x-item-disabled");
29995 this.disabled = true;
29996 this.el.disabled = true;
30000 * Enables this item.
30002 enable : function(){
30003 Roo.fly(this.td).removeClass("x-item-disabled");
30004 this.disabled = false;
30005 this.el.disabled = false;
30011 * @class Roo.Toolbar.Separator
30012 * @extends Roo.Toolbar.Item
30013 * A simple toolbar separator class
30015 * Creates a new Separator
30017 Roo.Toolbar.Separator = function(cfg){
30019 var s = document.createElement("span");
30020 s.className = "ytb-sep";
30025 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30027 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30028 enable:Roo.emptyFn,
30029 disable:Roo.emptyFn,
30034 * @class Roo.Toolbar.Spacer
30035 * @extends Roo.Toolbar.Item
30036 * A simple element that adds extra horizontal space to a toolbar.
30038 * Creates a new Spacer
30040 Roo.Toolbar.Spacer = function(cfg){
30041 var s = document.createElement("div");
30042 s.className = "ytb-spacer";
30046 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30048 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30049 enable:Roo.emptyFn,
30050 disable:Roo.emptyFn,
30055 * @class Roo.Toolbar.Fill
30056 * @extends Roo.Toolbar.Spacer
30057 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30059 * Creates a new Spacer
30061 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30063 render : function(td){
30064 td.style.width = '100%';
30065 Roo.Toolbar.Fill.superclass.render.call(this, td);
30070 * @class Roo.Toolbar.TextItem
30071 * @extends Roo.Toolbar.Item
30072 * A simple class that renders text directly into a toolbar.
30074 * Creates a new TextItem
30075 * @param {String} text
30077 Roo.Toolbar.TextItem = function(cfg){
30078 var text = cfg || "";
30079 if (typeof(cfg) == 'object') {
30080 text = cfg.text || "";
30084 var s = document.createElement("span");
30085 s.className = "ytb-text";
30086 s.innerHTML = text;
30091 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30093 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30096 enable:Roo.emptyFn,
30097 disable:Roo.emptyFn,
30102 * @class Roo.Toolbar.Button
30103 * @extends Roo.Button
30104 * A button that renders into a toolbar.
30106 * Creates a new Button
30107 * @param {Object} config A standard {@link Roo.Button} config object
30109 Roo.Toolbar.Button = function(config){
30110 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30112 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30113 render : function(td){
30115 Roo.Toolbar.Button.superclass.render.call(this, td);
30119 * Removes and destroys this button
30121 destroy : function(){
30122 Roo.Toolbar.Button.superclass.destroy.call(this);
30123 this.td.parentNode.removeChild(this.td);
30127 * Shows this button
30130 this.hidden = false;
30131 this.td.style.display = "";
30135 * Hides this button
30138 this.hidden = true;
30139 this.td.style.display = "none";
30143 * Disables this item
30145 disable : function(){
30146 Roo.fly(this.td).addClass("x-item-disabled");
30147 this.disabled = true;
30151 * Enables this item
30153 enable : function(){
30154 Roo.fly(this.td).removeClass("x-item-disabled");
30155 this.disabled = false;
30158 // backwards compat
30159 Roo.ToolbarButton = Roo.Toolbar.Button;
30162 * @class Roo.Toolbar.SplitButton
30163 * @extends Roo.SplitButton
30164 * A menu button that renders into a toolbar.
30166 * Creates a new SplitButton
30167 * @param {Object} config A standard {@link Roo.SplitButton} config object
30169 Roo.Toolbar.SplitButton = function(config){
30170 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30172 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30173 render : function(td){
30175 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30179 * Removes and destroys this button
30181 destroy : function(){
30182 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30183 this.td.parentNode.removeChild(this.td);
30187 * Shows this button
30190 this.hidden = false;
30191 this.td.style.display = "";
30195 * Hides this button
30198 this.hidden = true;
30199 this.td.style.display = "none";
30203 // backwards compat
30204 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30206 * Ext JS Library 1.1.1
30207 * Copyright(c) 2006-2007, Ext JS, LLC.
30209 * Originally Released Under LGPL - original licence link has changed is not relivant.
30212 * <script type="text/javascript">
30216 * @class Roo.PagingToolbar
30217 * @extends Roo.Toolbar
30218 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30220 * Create a new PagingToolbar
30221 * @param {Object} config The config object
30223 Roo.PagingToolbar = function(el, ds, config)
30225 // old args format still supported... - xtype is prefered..
30226 if (typeof(el) == 'object' && el.xtype) {
30227 // created from xtype...
30229 ds = el.dataSource;
30230 el = config.container;
30233 if (config.items) {
30234 items = config.items;
30238 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30241 this.renderButtons(this.el);
30244 // supprot items array.
30246 Roo.each(items, function(e) {
30247 this.add(Roo.factory(e));
30252 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30254 * @cfg {Roo.data.Store} dataSource
30255 * The underlying data store providing the paged data
30258 * @cfg {String/HTMLElement/Element} container
30259 * container The id or element that will contain the toolbar
30262 * @cfg {Boolean} displayInfo
30263 * True to display the displayMsg (defaults to false)
30266 * @cfg {Number} pageSize
30267 * The number of records to display per page (defaults to 20)
30271 * @cfg {String} displayMsg
30272 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30274 displayMsg : 'Displaying {0} - {1} of {2}',
30276 * @cfg {String} emptyMsg
30277 * The message to display when no records are found (defaults to "No data to display")
30279 emptyMsg : 'No data to display',
30281 * Customizable piece of the default paging text (defaults to "Page")
30284 beforePageText : "Page",
30286 * Customizable piece of the default paging text (defaults to "of %0")
30289 afterPageText : "of {0}",
30291 * Customizable piece of the default paging text (defaults to "First Page")
30294 firstText : "First Page",
30296 * Customizable piece of the default paging text (defaults to "Previous Page")
30299 prevText : "Previous Page",
30301 * Customizable piece of the default paging text (defaults to "Next Page")
30304 nextText : "Next Page",
30306 * Customizable piece of the default paging text (defaults to "Last Page")
30309 lastText : "Last Page",
30311 * Customizable piece of the default paging text (defaults to "Refresh")
30314 refreshText : "Refresh",
30317 renderButtons : function(el){
30318 Roo.PagingToolbar.superclass.render.call(this, el);
30319 this.first = this.addButton({
30320 tooltip: this.firstText,
30321 cls: "x-btn-icon x-grid-page-first",
30323 handler: this.onClick.createDelegate(this, ["first"])
30325 this.prev = this.addButton({
30326 tooltip: this.prevText,
30327 cls: "x-btn-icon x-grid-page-prev",
30329 handler: this.onClick.createDelegate(this, ["prev"])
30331 //this.addSeparator();
30332 this.add(this.beforePageText);
30333 this.field = Roo.get(this.addDom({
30338 cls: "x-grid-page-number"
30340 this.field.on("keydown", this.onPagingKeydown, this);
30341 this.field.on("focus", function(){this.dom.select();});
30342 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30343 this.field.setHeight(18);
30344 //this.addSeparator();
30345 this.next = this.addButton({
30346 tooltip: this.nextText,
30347 cls: "x-btn-icon x-grid-page-next",
30349 handler: this.onClick.createDelegate(this, ["next"])
30351 this.last = this.addButton({
30352 tooltip: this.lastText,
30353 cls: "x-btn-icon x-grid-page-last",
30355 handler: this.onClick.createDelegate(this, ["last"])
30357 //this.addSeparator();
30358 this.loading = this.addButton({
30359 tooltip: this.refreshText,
30360 cls: "x-btn-icon x-grid-loading",
30361 handler: this.onClick.createDelegate(this, ["refresh"])
30364 if(this.displayInfo){
30365 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30370 updateInfo : function(){
30371 if(this.displayEl){
30372 var count = this.ds.getCount();
30373 var msg = count == 0 ?
30377 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30379 this.displayEl.update(msg);
30384 onLoad : function(ds, r, o){
30385 this.cursor = o.params ? o.params.start : 0;
30386 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30388 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30389 this.field.dom.value = ap;
30390 this.first.setDisabled(ap == 1);
30391 this.prev.setDisabled(ap == 1);
30392 this.next.setDisabled(ap == ps);
30393 this.last.setDisabled(ap == ps);
30394 this.loading.enable();
30399 getPageData : function(){
30400 var total = this.ds.getTotalCount();
30403 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30404 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30409 onLoadError : function(){
30410 this.loading.enable();
30414 onPagingKeydown : function(e){
30415 var k = e.getKey();
30416 var d = this.getPageData();
30418 var v = this.field.dom.value, pageNum;
30419 if(!v || isNaN(pageNum = parseInt(v, 10))){
30420 this.field.dom.value = d.activePage;
30423 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30424 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30427 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))
30429 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30430 this.field.dom.value = pageNum;
30431 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30434 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30436 var v = this.field.dom.value, pageNum;
30437 var increment = (e.shiftKey) ? 10 : 1;
30438 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30441 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30442 this.field.dom.value = d.activePage;
30445 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30447 this.field.dom.value = parseInt(v, 10) + increment;
30448 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30449 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30456 beforeLoad : function(){
30458 this.loading.disable();
30463 onClick : function(which){
30467 ds.load({params:{start: 0, limit: this.pageSize}});
30470 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30473 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30476 var total = ds.getTotalCount();
30477 var extra = total % this.pageSize;
30478 var lastStart = extra ? (total - extra) : total-this.pageSize;
30479 ds.load({params:{start: lastStart, limit: this.pageSize}});
30482 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30488 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30489 * @param {Roo.data.Store} store The data store to unbind
30491 unbind : function(ds){
30492 ds.un("beforeload", this.beforeLoad, this);
30493 ds.un("load", this.onLoad, this);
30494 ds.un("loadexception", this.onLoadError, this);
30495 ds.un("remove", this.updateInfo, this);
30496 ds.un("add", this.updateInfo, this);
30497 this.ds = undefined;
30501 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30502 * @param {Roo.data.Store} store The data store to bind
30504 bind : function(ds){
30505 ds.on("beforeload", this.beforeLoad, this);
30506 ds.on("load", this.onLoad, this);
30507 ds.on("loadexception", this.onLoadError, this);
30508 ds.on("remove", this.updateInfo, this);
30509 ds.on("add", this.updateInfo, this);
30514 * Ext JS Library 1.1.1
30515 * Copyright(c) 2006-2007, Ext JS, LLC.
30517 * Originally Released Under LGPL - original licence link has changed is not relivant.
30520 * <script type="text/javascript">
30524 * @class Roo.Resizable
30525 * @extends Roo.util.Observable
30526 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30527 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30528 * 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
30529 * the element will be wrapped for you automatically.</p>
30530 * <p>Here is the list of valid resize handles:</p>
30533 ------ -------------------
30542 'hd' horizontal drag
30545 * <p>Here's an example showing the creation of a typical Resizable:</p>
30547 var resizer = new Roo.Resizable("element-id", {
30555 resizer.on("resize", myHandler);
30557 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30558 * resizer.east.setDisplayed(false);</p>
30559 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30560 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30561 * resize operation's new size (defaults to [0, 0])
30562 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30563 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30564 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30565 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30566 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30567 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30568 * @cfg {Number} width The width of the element in pixels (defaults to null)
30569 * @cfg {Number} height The height of the element in pixels (defaults to null)
30570 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30571 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30572 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30573 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30574 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30575 * in favor of the handles config option (defaults to false)
30576 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30577 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30578 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30579 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30580 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30581 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30582 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30583 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30584 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30585 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30586 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30588 * Create a new resizable component
30589 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30590 * @param {Object} config configuration options
30592 Roo.Resizable = function(el, config)
30594 this.el = Roo.get(el);
30596 if(config && config.wrap){
30597 config.resizeChild = this.el;
30598 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30599 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30600 this.el.setStyle("overflow", "hidden");
30601 this.el.setPositioning(config.resizeChild.getPositioning());
30602 config.resizeChild.clearPositioning();
30603 if(!config.width || !config.height){
30604 var csize = config.resizeChild.getSize();
30605 this.el.setSize(csize.width, csize.height);
30607 if(config.pinned && !config.adjustments){
30608 config.adjustments = "auto";
30612 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30613 this.proxy.unselectable();
30614 this.proxy.enableDisplayMode('block');
30616 Roo.apply(this, config);
30619 this.disableTrackOver = true;
30620 this.el.addClass("x-resizable-pinned");
30622 // if the element isn't positioned, make it relative
30623 var position = this.el.getStyle("position");
30624 if(position != "absolute" && position != "fixed"){
30625 this.el.setStyle("position", "relative");
30627 if(!this.handles){ // no handles passed, must be legacy style
30628 this.handles = 's,e,se';
30629 if(this.multiDirectional){
30630 this.handles += ',n,w';
30633 if(this.handles == "all"){
30634 this.handles = "n s e w ne nw se sw";
30636 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30637 var ps = Roo.Resizable.positions;
30638 for(var i = 0, len = hs.length; i < len; i++){
30639 if(hs[i] && ps[hs[i]]){
30640 var pos = ps[hs[i]];
30641 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30645 this.corner = this.southeast;
30647 // updateBox = the box can move..
30648 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30649 this.updateBox = true;
30652 this.activeHandle = null;
30654 if(this.resizeChild){
30655 if(typeof this.resizeChild == "boolean"){
30656 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30658 this.resizeChild = Roo.get(this.resizeChild, true);
30662 if(this.adjustments == "auto"){
30663 var rc = this.resizeChild;
30664 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30665 if(rc && (hw || hn)){
30666 rc.position("relative");
30667 rc.setLeft(hw ? hw.el.getWidth() : 0);
30668 rc.setTop(hn ? hn.el.getHeight() : 0);
30670 this.adjustments = [
30671 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30672 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30676 if(this.draggable){
30677 this.dd = this.dynamic ?
30678 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30679 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30685 * @event beforeresize
30686 * Fired before resize is allowed. Set enabled to false to cancel resize.
30687 * @param {Roo.Resizable} this
30688 * @param {Roo.EventObject} e The mousedown event
30690 "beforeresize" : true,
30693 * Fired a resizing.
30694 * @param {Roo.Resizable} this
30695 * @param {Number} x The new x position
30696 * @param {Number} y The new y position
30697 * @param {Number} w The new w width
30698 * @param {Number} h The new h hight
30699 * @param {Roo.EventObject} e The mouseup event
30704 * Fired after a resize.
30705 * @param {Roo.Resizable} this
30706 * @param {Number} width The new width
30707 * @param {Number} height The new height
30708 * @param {Roo.EventObject} e The mouseup event
30713 if(this.width !== null && this.height !== null){
30714 this.resizeTo(this.width, this.height);
30716 this.updateChildSize();
30719 this.el.dom.style.zoom = 1;
30721 Roo.Resizable.superclass.constructor.call(this);
30724 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30725 resizeChild : false,
30726 adjustments : [0, 0],
30736 multiDirectional : false,
30737 disableTrackOver : false,
30738 easing : 'easeOutStrong',
30739 widthIncrement : 0,
30740 heightIncrement : 0,
30744 preserveRatio : false,
30745 transparent: false,
30751 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30753 constrainTo: undefined,
30755 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30757 resizeRegion: undefined,
30761 * Perform a manual resize
30762 * @param {Number} width
30763 * @param {Number} height
30765 resizeTo : function(width, height){
30766 this.el.setSize(width, height);
30767 this.updateChildSize();
30768 this.fireEvent("resize", this, width, height, null);
30772 startSizing : function(e, handle){
30773 this.fireEvent("beforeresize", this, e);
30774 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30777 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30778 this.overlay.unselectable();
30779 this.overlay.enableDisplayMode("block");
30780 this.overlay.on("mousemove", this.onMouseMove, this);
30781 this.overlay.on("mouseup", this.onMouseUp, this);
30783 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30785 this.resizing = true;
30786 this.startBox = this.el.getBox();
30787 this.startPoint = e.getXY();
30788 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30789 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30791 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30792 this.overlay.show();
30794 if(this.constrainTo) {
30795 var ct = Roo.get(this.constrainTo);
30796 this.resizeRegion = ct.getRegion().adjust(
30797 ct.getFrameWidth('t'),
30798 ct.getFrameWidth('l'),
30799 -ct.getFrameWidth('b'),
30800 -ct.getFrameWidth('r')
30804 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30806 this.proxy.setBox(this.startBox);
30808 this.proxy.setStyle('visibility', 'visible');
30814 onMouseDown : function(handle, e){
30817 this.activeHandle = handle;
30818 this.startSizing(e, handle);
30823 onMouseUp : function(e){
30824 var size = this.resizeElement();
30825 this.resizing = false;
30827 this.overlay.hide();
30829 this.fireEvent("resize", this, size.width, size.height, e);
30833 updateChildSize : function(){
30835 if(this.resizeChild){
30837 var child = this.resizeChild;
30838 var adj = this.adjustments;
30839 if(el.dom.offsetWidth){
30840 var b = el.getSize(true);
30841 child.setSize(b.width+adj[0], b.height+adj[1]);
30843 // Second call here for IE
30844 // The first call enables instant resizing and
30845 // the second call corrects scroll bars if they
30848 setTimeout(function(){
30849 if(el.dom.offsetWidth){
30850 var b = el.getSize(true);
30851 child.setSize(b.width+adj[0], b.height+adj[1]);
30859 snap : function(value, inc, min){
30860 if(!inc || !value) {
30863 var newValue = value;
30864 var m = value % inc;
30867 newValue = value + (inc-m);
30869 newValue = value - m;
30872 return Math.max(min, newValue);
30876 resizeElement : function(){
30877 var box = this.proxy.getBox();
30878 if(this.updateBox){
30879 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
30881 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
30883 this.updateChildSize();
30891 constrain : function(v, diff, m, mx){
30894 }else if(v - diff > mx){
30901 onMouseMove : function(e){
30904 try{// try catch so if something goes wrong the user doesn't get hung
30906 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
30910 //var curXY = this.startPoint;
30911 var curSize = this.curSize || this.startBox;
30912 var x = this.startBox.x, y = this.startBox.y;
30913 var ox = x, oy = y;
30914 var w = curSize.width, h = curSize.height;
30915 var ow = w, oh = h;
30916 var mw = this.minWidth, mh = this.minHeight;
30917 var mxw = this.maxWidth, mxh = this.maxHeight;
30918 var wi = this.widthIncrement;
30919 var hi = this.heightIncrement;
30921 var eventXY = e.getXY();
30922 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
30923 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
30925 var pos = this.activeHandle.position;
30930 w = Math.min(Math.max(mw, w), mxw);
30935 h = Math.min(Math.max(mh, h), mxh);
30940 w = Math.min(Math.max(mw, w), mxw);
30941 h = Math.min(Math.max(mh, h), mxh);
30944 diffY = this.constrain(h, diffY, mh, mxh);
30951 var adiffX = Math.abs(diffX);
30952 var sub = (adiffX % wi); // how much
30953 if (sub > (wi/2)) { // far enough to snap
30954 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
30956 // remove difference..
30957 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
30961 x = Math.max(this.minX, x);
30964 diffX = this.constrain(w, diffX, mw, mxw);
30970 w = Math.min(Math.max(mw, w), mxw);
30971 diffY = this.constrain(h, diffY, mh, mxh);
30976 diffX = this.constrain(w, diffX, mw, mxw);
30977 diffY = this.constrain(h, diffY, mh, mxh);
30984 diffX = this.constrain(w, diffX, mw, mxw);
30986 h = Math.min(Math.max(mh, h), mxh);
30992 var sw = this.snap(w, wi, mw);
30993 var sh = this.snap(h, hi, mh);
30994 if(sw != w || sh != h){
31017 if(this.preserveRatio){
31022 h = Math.min(Math.max(mh, h), mxh);
31027 w = Math.min(Math.max(mw, w), mxw);
31032 w = Math.min(Math.max(mw, w), mxw);
31038 w = Math.min(Math.max(mw, w), mxw);
31044 h = Math.min(Math.max(mh, h), mxh);
31052 h = Math.min(Math.max(mh, h), mxh);
31062 h = Math.min(Math.max(mh, h), mxh);
31070 if (pos == 'hdrag') {
31073 this.proxy.setBounds(x, y, w, h);
31075 this.resizeElement();
31079 this.fireEvent("resizing", this, x, y, w, h, e);
31083 handleOver : function(){
31085 this.el.addClass("x-resizable-over");
31090 handleOut : function(){
31091 if(!this.resizing){
31092 this.el.removeClass("x-resizable-over");
31097 * Returns the element this component is bound to.
31098 * @return {Roo.Element}
31100 getEl : function(){
31105 * Returns the resizeChild element (or null).
31106 * @return {Roo.Element}
31108 getResizeChild : function(){
31109 return this.resizeChild;
31111 groupHandler : function()
31116 * Destroys this resizable. If the element was wrapped and
31117 * removeEl is not true then the element remains.
31118 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31120 destroy : function(removeEl){
31121 this.proxy.remove();
31123 this.overlay.removeAllListeners();
31124 this.overlay.remove();
31126 var ps = Roo.Resizable.positions;
31128 if(typeof ps[k] != "function" && this[ps[k]]){
31129 var h = this[ps[k]];
31130 h.el.removeAllListeners();
31135 this.el.update("");
31142 // hash to map config positions to true positions
31143 Roo.Resizable.positions = {
31144 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31149 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31151 // only initialize the template if resizable is used
31152 var tpl = Roo.DomHelper.createTemplate(
31153 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31156 Roo.Resizable.Handle.prototype.tpl = tpl;
31158 this.position = pos;
31160 // show north drag fro topdra
31161 var handlepos = pos == 'hdrag' ? 'north' : pos;
31163 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31164 if (pos == 'hdrag') {
31165 this.el.setStyle('cursor', 'pointer');
31167 this.el.unselectable();
31169 this.el.setOpacity(0);
31171 this.el.on("mousedown", this.onMouseDown, this);
31172 if(!disableTrackOver){
31173 this.el.on("mouseover", this.onMouseOver, this);
31174 this.el.on("mouseout", this.onMouseOut, this);
31179 Roo.Resizable.Handle.prototype = {
31180 afterResize : function(rz){
31185 onMouseDown : function(e){
31186 this.rz.onMouseDown(this, e);
31189 onMouseOver : function(e){
31190 this.rz.handleOver(this, e);
31193 onMouseOut : function(e){
31194 this.rz.handleOut(this, e);
31198 * Ext JS Library 1.1.1
31199 * Copyright(c) 2006-2007, Ext JS, LLC.
31201 * Originally Released Under LGPL - original licence link has changed is not relivant.
31204 * <script type="text/javascript">
31208 * @class Roo.Editor
31209 * @extends Roo.Component
31210 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31212 * Create a new Editor
31213 * @param {Roo.form.Field} field The Field object (or descendant)
31214 * @param {Object} config The config object
31216 Roo.Editor = function(field, config){
31217 Roo.Editor.superclass.constructor.call(this, config);
31218 this.field = field;
31221 * @event beforestartedit
31222 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31223 * false from the handler of this event.
31224 * @param {Editor} this
31225 * @param {Roo.Element} boundEl The underlying element bound to this editor
31226 * @param {Mixed} value The field value being set
31228 "beforestartedit" : true,
31231 * Fires when this editor is displayed
31232 * @param {Roo.Element} boundEl The underlying element bound to this editor
31233 * @param {Mixed} value The starting field value
31235 "startedit" : true,
31237 * @event beforecomplete
31238 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31239 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31240 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31241 * event will not fire since no edit actually occurred.
31242 * @param {Editor} this
31243 * @param {Mixed} value The current field value
31244 * @param {Mixed} startValue The original field value
31246 "beforecomplete" : true,
31249 * Fires after editing is complete and any changed value has been written to the underlying field.
31250 * @param {Editor} this
31251 * @param {Mixed} value The current field value
31252 * @param {Mixed} startValue The original field value
31256 * @event specialkey
31257 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31258 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31259 * @param {Roo.form.Field} this
31260 * @param {Roo.EventObject} e The event object
31262 "specialkey" : true
31266 Roo.extend(Roo.Editor, Roo.Component, {
31268 * @cfg {Boolean/String} autosize
31269 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31270 * or "height" to adopt the height only (defaults to false)
31273 * @cfg {Boolean} revertInvalid
31274 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31275 * validation fails (defaults to true)
31278 * @cfg {Boolean} ignoreNoChange
31279 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31280 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31281 * will never be ignored.
31284 * @cfg {Boolean} hideEl
31285 * False to keep the bound element visible while the editor is displayed (defaults to true)
31288 * @cfg {Mixed} value
31289 * The data value of the underlying field (defaults to "")
31293 * @cfg {String} alignment
31294 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31298 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31299 * for bottom-right shadow (defaults to "frame")
31303 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31307 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31309 completeOnEnter : false,
31311 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31313 cancelOnEsc : false,
31315 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31320 onRender : function(ct, position){
31321 this.el = new Roo.Layer({
31322 shadow: this.shadow,
31328 constrain: this.constrain
31330 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31331 if(this.field.msgTarget != 'title'){
31332 this.field.msgTarget = 'qtip';
31334 this.field.render(this.el);
31336 this.field.el.dom.setAttribute('autocomplete', 'off');
31338 this.field.on("specialkey", this.onSpecialKey, this);
31339 if(this.swallowKeys){
31340 this.field.el.swallowEvent(['keydown','keypress']);
31343 this.field.on("blur", this.onBlur, this);
31344 if(this.field.grow){
31345 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31349 onSpecialKey : function(field, e)
31351 //Roo.log('editor onSpecialKey');
31352 if(this.completeOnEnter && e.getKey() == e.ENTER){
31354 this.completeEdit();
31357 // do not fire special key otherwise it might hide close the editor...
31358 if(e.getKey() == e.ENTER){
31361 if(this.cancelOnEsc && e.getKey() == e.ESC){
31365 this.fireEvent('specialkey', field, e);
31370 * Starts the editing process and shows the editor.
31371 * @param {String/HTMLElement/Element} el The element to edit
31372 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31373 * to the innerHTML of el.
31375 startEdit : function(el, value){
31377 this.completeEdit();
31379 this.boundEl = Roo.get(el);
31380 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31381 if(!this.rendered){
31382 this.render(this.parentEl || document.body);
31384 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31387 this.startValue = v;
31388 this.field.setValue(v);
31390 var sz = this.boundEl.getSize();
31391 switch(this.autoSize){
31393 this.setSize(sz.width, "");
31396 this.setSize("", sz.height);
31399 this.setSize(sz.width, sz.height);
31402 this.el.alignTo(this.boundEl, this.alignment);
31403 this.editing = true;
31405 Roo.QuickTips.disable();
31411 * Sets the height and width of this editor.
31412 * @param {Number} width The new width
31413 * @param {Number} height The new height
31415 setSize : function(w, h){
31416 this.field.setSize(w, h);
31423 * Realigns the editor to the bound field based on the current alignment config value.
31425 realign : function(){
31426 this.el.alignTo(this.boundEl, this.alignment);
31430 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31431 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31433 completeEdit : function(remainVisible){
31437 var v = this.getValue();
31438 if(this.revertInvalid !== false && !this.field.isValid()){
31439 v = this.startValue;
31440 this.cancelEdit(true);
31442 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31443 this.editing = false;
31447 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31448 this.editing = false;
31449 if(this.updateEl && this.boundEl){
31450 this.boundEl.update(v);
31452 if(remainVisible !== true){
31455 this.fireEvent("complete", this, v, this.startValue);
31460 onShow : function(){
31462 if(this.hideEl !== false){
31463 this.boundEl.hide();
31466 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31467 this.fixIEFocus = true;
31468 this.deferredFocus.defer(50, this);
31470 this.field.focus();
31472 this.fireEvent("startedit", this.boundEl, this.startValue);
31475 deferredFocus : function(){
31477 this.field.focus();
31482 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31483 * reverted to the original starting value.
31484 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31485 * cancel (defaults to false)
31487 cancelEdit : function(remainVisible){
31489 this.setValue(this.startValue);
31490 if(remainVisible !== true){
31497 onBlur : function(){
31498 if(this.allowBlur !== true && this.editing){
31499 this.completeEdit();
31504 onHide : function(){
31506 this.completeEdit();
31510 if(this.field.collapse){
31511 this.field.collapse();
31514 if(this.hideEl !== false){
31515 this.boundEl.show();
31518 Roo.QuickTips.enable();
31523 * Sets the data value of the editor
31524 * @param {Mixed} value Any valid value supported by the underlying field
31526 setValue : function(v){
31527 this.field.setValue(v);
31531 * Gets the data value of the editor
31532 * @return {Mixed} The data value
31534 getValue : function(){
31535 return this.field.getValue();
31539 * Ext JS Library 1.1.1
31540 * Copyright(c) 2006-2007, Ext JS, LLC.
31542 * Originally Released Under LGPL - original licence link has changed is not relivant.
31545 * <script type="text/javascript">
31549 * @class Roo.BasicDialog
31550 * @extends Roo.util.Observable
31551 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31553 var dlg = new Roo.BasicDialog("my-dlg", {
31562 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31563 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31564 dlg.addButton('Cancel', dlg.hide, dlg);
31567 <b>A Dialog should always be a direct child of the body element.</b>
31568 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31569 * @cfg {String} title Default text to display in the title bar (defaults to null)
31570 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31571 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31572 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31573 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31574 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31575 * (defaults to null with no animation)
31576 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31577 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31578 * property for valid values (defaults to 'all')
31579 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31580 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31581 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31582 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31583 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31584 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31585 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31586 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31587 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31588 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31589 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31590 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31591 * draggable = true (defaults to false)
31592 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31593 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31594 * shadow (defaults to false)
31595 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31596 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31597 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31598 * @cfg {Array} buttons Array of buttons
31599 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31601 * Create a new BasicDialog.
31602 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31603 * @param {Object} config Configuration options
31605 Roo.BasicDialog = function(el, config){
31606 this.el = Roo.get(el);
31607 var dh = Roo.DomHelper;
31608 if(!this.el && config && config.autoCreate){
31609 if(typeof config.autoCreate == "object"){
31610 if(!config.autoCreate.id){
31611 config.autoCreate.id = el;
31613 this.el = dh.append(document.body,
31614 config.autoCreate, true);
31616 this.el = dh.append(document.body,
31617 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31621 el.setDisplayed(true);
31622 el.hide = this.hideAction;
31624 el.addClass("x-dlg");
31626 Roo.apply(this, config);
31628 this.proxy = el.createProxy("x-dlg-proxy");
31629 this.proxy.hide = this.hideAction;
31630 this.proxy.setOpacity(.5);
31634 el.setWidth(config.width);
31637 el.setHeight(config.height);
31639 this.size = el.getSize();
31640 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31641 this.xy = [config.x,config.y];
31643 this.xy = el.getCenterXY(true);
31645 /** The header element @type Roo.Element */
31646 this.header = el.child("> .x-dlg-hd");
31647 /** The body element @type Roo.Element */
31648 this.body = el.child("> .x-dlg-bd");
31649 /** The footer element @type Roo.Element */
31650 this.footer = el.child("> .x-dlg-ft");
31653 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31656 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31659 this.header.unselectable();
31661 this.header.update(this.title);
31663 // this element allows the dialog to be focused for keyboard event
31664 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31665 this.focusEl.swallowEvent("click", true);
31667 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31669 // wrap the body and footer for special rendering
31670 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31672 this.bwrap.dom.appendChild(this.footer.dom);
31675 this.bg = this.el.createChild({
31676 tag: "div", cls:"x-dlg-bg",
31677 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31679 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31682 if(this.autoScroll !== false && !this.autoTabs){
31683 this.body.setStyle("overflow", "auto");
31686 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31688 if(this.closable !== false){
31689 this.el.addClass("x-dlg-closable");
31690 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31691 this.close.on("click", this.closeClick, this);
31692 this.close.addClassOnOver("x-dlg-close-over");
31694 if(this.collapsible !== false){
31695 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31696 this.collapseBtn.on("click", this.collapseClick, this);
31697 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31698 this.header.on("dblclick", this.collapseClick, this);
31700 if(this.resizable !== false){
31701 this.el.addClass("x-dlg-resizable");
31702 this.resizer = new Roo.Resizable(el, {
31703 minWidth: this.minWidth || 80,
31704 minHeight:this.minHeight || 80,
31705 handles: this.resizeHandles || "all",
31708 this.resizer.on("beforeresize", this.beforeResize, this);
31709 this.resizer.on("resize", this.onResize, this);
31711 if(this.draggable !== false){
31712 el.addClass("x-dlg-draggable");
31713 if (!this.proxyDrag) {
31714 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31717 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31719 dd.setHandleElId(this.header.id);
31720 dd.endDrag = this.endMove.createDelegate(this);
31721 dd.startDrag = this.startMove.createDelegate(this);
31722 dd.onDrag = this.onDrag.createDelegate(this);
31727 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31728 this.mask.enableDisplayMode("block");
31730 this.el.addClass("x-dlg-modal");
31733 this.shadow = new Roo.Shadow({
31734 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31735 offset : this.shadowOffset
31738 this.shadowOffset = 0;
31740 if(Roo.useShims && this.shim !== false){
31741 this.shim = this.el.createShim();
31742 this.shim.hide = this.hideAction;
31750 if (this.buttons) {
31751 var bts= this.buttons;
31753 Roo.each(bts, function(b) {
31762 * Fires when a key is pressed
31763 * @param {Roo.BasicDialog} this
31764 * @param {Roo.EventObject} e
31769 * Fires when this dialog is moved by the user.
31770 * @param {Roo.BasicDialog} this
31771 * @param {Number} x The new page X
31772 * @param {Number} y The new page Y
31777 * Fires when this dialog is resized by the user.
31778 * @param {Roo.BasicDialog} this
31779 * @param {Number} width The new width
31780 * @param {Number} height The new height
31784 * @event beforehide
31785 * Fires before this dialog is hidden.
31786 * @param {Roo.BasicDialog} this
31788 "beforehide" : true,
31791 * Fires when this dialog is hidden.
31792 * @param {Roo.BasicDialog} this
31796 * @event beforeshow
31797 * Fires before this dialog is shown.
31798 * @param {Roo.BasicDialog} this
31800 "beforeshow" : true,
31803 * Fires when this dialog is shown.
31804 * @param {Roo.BasicDialog} this
31808 el.on("keydown", this.onKeyDown, this);
31809 el.on("mousedown", this.toFront, this);
31810 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31812 Roo.DialogManager.register(this);
31813 Roo.BasicDialog.superclass.constructor.call(this);
31816 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31817 shadowOffset: Roo.isIE ? 6 : 5,
31820 minButtonWidth: 75,
31821 defaultButton: null,
31822 buttonAlign: "right",
31827 * Sets the dialog title text
31828 * @param {String} text The title text to display
31829 * @return {Roo.BasicDialog} this
31831 setTitle : function(text){
31832 this.header.update(text);
31837 closeClick : function(){
31842 collapseClick : function(){
31843 this[this.collapsed ? "expand" : "collapse"]();
31847 * Collapses the dialog to its minimized state (only the title bar is visible).
31848 * Equivalent to the user clicking the collapse dialog button.
31850 collapse : function(){
31851 if(!this.collapsed){
31852 this.collapsed = true;
31853 this.el.addClass("x-dlg-collapsed");
31854 this.restoreHeight = this.el.getHeight();
31855 this.resizeTo(this.el.getWidth(), this.header.getHeight());
31860 * Expands a collapsed dialog back to its normal state. Equivalent to the user
31861 * clicking the expand dialog button.
31863 expand : function(){
31864 if(this.collapsed){
31865 this.collapsed = false;
31866 this.el.removeClass("x-dlg-collapsed");
31867 this.resizeTo(this.el.getWidth(), this.restoreHeight);
31872 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
31873 * @return {Roo.TabPanel} The tabs component
31875 initTabs : function(){
31876 var tabs = this.getTabs();
31877 while(tabs.getTab(0)){
31880 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
31882 tabs.addTab(Roo.id(dom), dom.title);
31890 beforeResize : function(){
31891 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
31895 onResize : function(){
31896 this.refreshSize();
31897 this.syncBodyHeight();
31898 this.adjustAssets();
31900 this.fireEvent("resize", this, this.size.width, this.size.height);
31904 onKeyDown : function(e){
31905 if(this.isVisible()){
31906 this.fireEvent("keydown", this, e);
31911 * Resizes the dialog.
31912 * @param {Number} width
31913 * @param {Number} height
31914 * @return {Roo.BasicDialog} this
31916 resizeTo : function(width, height){
31917 this.el.setSize(width, height);
31918 this.size = {width: width, height: height};
31919 this.syncBodyHeight();
31920 if(this.fixedcenter){
31923 if(this.isVisible()){
31924 this.constrainXY();
31925 this.adjustAssets();
31927 this.fireEvent("resize", this, width, height);
31933 * Resizes the dialog to fit the specified content size.
31934 * @param {Number} width
31935 * @param {Number} height
31936 * @return {Roo.BasicDialog} this
31938 setContentSize : function(w, h){
31939 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
31940 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
31941 //if(!this.el.isBorderBox()){
31942 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
31943 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
31946 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
31947 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
31949 this.resizeTo(w, h);
31954 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
31955 * executed in response to a particular key being pressed while the dialog is active.
31956 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
31957 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
31958 * @param {Function} fn The function to call
31959 * @param {Object} scope (optional) The scope of the function
31960 * @return {Roo.BasicDialog} this
31962 addKeyListener : function(key, fn, scope){
31963 var keyCode, shift, ctrl, alt;
31964 if(typeof key == "object" && !(key instanceof Array)){
31965 keyCode = key["key"];
31966 shift = key["shift"];
31967 ctrl = key["ctrl"];
31972 var handler = function(dlg, e){
31973 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
31974 var k = e.getKey();
31975 if(keyCode instanceof Array){
31976 for(var i = 0, len = keyCode.length; i < len; i++){
31977 if(keyCode[i] == k){
31978 fn.call(scope || window, dlg, k, e);
31984 fn.call(scope || window, dlg, k, e);
31989 this.on("keydown", handler);
31994 * Returns the TabPanel component (creates it if it doesn't exist).
31995 * Note: If you wish to simply check for the existence of tabs without creating them,
31996 * check for a null 'tabs' property.
31997 * @return {Roo.TabPanel} The tabs component
31999 getTabs : function(){
32001 this.el.addClass("x-dlg-auto-tabs");
32002 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32003 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32009 * Adds a button to the footer section of the dialog.
32010 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32011 * object or a valid Roo.DomHelper element config
32012 * @param {Function} handler The function called when the button is clicked
32013 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32014 * @return {Roo.Button} The new button
32016 addButton : function(config, handler, scope){
32017 var dh = Roo.DomHelper;
32019 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32021 if(!this.btnContainer){
32022 var tb = this.footer.createChild({
32024 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32025 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32027 this.btnContainer = tb.firstChild.firstChild.firstChild;
32032 minWidth: this.minButtonWidth,
32035 if(typeof config == "string"){
32036 bconfig.text = config;
32039 bconfig.dhconfig = config;
32041 Roo.apply(bconfig, config);
32045 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32046 bconfig.position = Math.max(0, bconfig.position);
32047 fc = this.btnContainer.childNodes[bconfig.position];
32050 var btn = new Roo.Button(
32052 this.btnContainer.insertBefore(document.createElement("td"),fc)
32053 : this.btnContainer.appendChild(document.createElement("td")),
32054 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32057 this.syncBodyHeight();
32060 * Array of all the buttons that have been added to this dialog via addButton
32065 this.buttons.push(btn);
32070 * Sets the default button to be focused when the dialog is displayed.
32071 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32072 * @return {Roo.BasicDialog} this
32074 setDefaultButton : function(btn){
32075 this.defaultButton = btn;
32080 getHeaderFooterHeight : function(safe){
32083 height += this.header.getHeight();
32086 var fm = this.footer.getMargins();
32087 height += (this.footer.getHeight()+fm.top+fm.bottom);
32089 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32090 height += this.centerBg.getPadding("tb");
32095 syncBodyHeight : function()
32097 var bd = this.body, // the text
32098 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32100 var height = this.size.height - this.getHeaderFooterHeight(false);
32101 bd.setHeight(height-bd.getMargins("tb"));
32102 var hh = this.header.getHeight();
32103 var h = this.size.height-hh;
32106 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32107 bw.setHeight(h-cb.getPadding("tb"));
32109 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32110 bd.setWidth(bw.getWidth(true));
32112 this.tabs.syncHeight();
32114 this.tabs.el.repaint();
32120 * Restores the previous state of the dialog if Roo.state is configured.
32121 * @return {Roo.BasicDialog} this
32123 restoreState : function(){
32124 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32125 if(box && box.width){
32126 this.xy = [box.x, box.y];
32127 this.resizeTo(box.width, box.height);
32133 beforeShow : function(){
32135 if(this.fixedcenter){
32136 this.xy = this.el.getCenterXY(true);
32139 Roo.get(document.body).addClass("x-body-masked");
32140 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32143 this.constrainXY();
32147 animShow : function(){
32148 var b = Roo.get(this.animateTarget).getBox();
32149 this.proxy.setSize(b.width, b.height);
32150 this.proxy.setLocation(b.x, b.y);
32152 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32153 true, .35, this.showEl.createDelegate(this));
32157 * Shows the dialog.
32158 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32159 * @return {Roo.BasicDialog} this
32161 show : function(animateTarget){
32162 if (this.fireEvent("beforeshow", this) === false){
32165 if(this.syncHeightBeforeShow){
32166 this.syncBodyHeight();
32167 }else if(this.firstShow){
32168 this.firstShow = false;
32169 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32171 this.animateTarget = animateTarget || this.animateTarget;
32172 if(!this.el.isVisible()){
32174 if(this.animateTarget && Roo.get(this.animateTarget)){
32184 showEl : function(){
32186 this.el.setXY(this.xy);
32188 this.adjustAssets(true);
32191 // IE peekaboo bug - fix found by Dave Fenwick
32195 this.fireEvent("show", this);
32199 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32200 * dialog itself will receive focus.
32202 focus : function(){
32203 if(this.defaultButton){
32204 this.defaultButton.focus();
32206 this.focusEl.focus();
32211 constrainXY : function(){
32212 if(this.constraintoviewport !== false){
32213 if(!this.viewSize){
32214 if(this.container){
32215 var s = this.container.getSize();
32216 this.viewSize = [s.width, s.height];
32218 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32221 var s = Roo.get(this.container||document).getScroll();
32223 var x = this.xy[0], y = this.xy[1];
32224 var w = this.size.width, h = this.size.height;
32225 var vw = this.viewSize[0], vh = this.viewSize[1];
32226 // only move it if it needs it
32228 // first validate right/bottom
32229 if(x + w > vw+s.left){
32233 if(y + h > vh+s.top){
32237 // then make sure top/left isn't negative
32249 if(this.isVisible()){
32250 this.el.setLocation(x, y);
32251 this.adjustAssets();
32258 onDrag : function(){
32259 if(!this.proxyDrag){
32260 this.xy = this.el.getXY();
32261 this.adjustAssets();
32266 adjustAssets : function(doShow){
32267 var x = this.xy[0], y = this.xy[1];
32268 var w = this.size.width, h = this.size.height;
32269 if(doShow === true){
32271 this.shadow.show(this.el);
32277 if(this.shadow && this.shadow.isVisible()){
32278 this.shadow.show(this.el);
32280 if(this.shim && this.shim.isVisible()){
32281 this.shim.setBounds(x, y, w, h);
32286 adjustViewport : function(w, h){
32288 w = Roo.lib.Dom.getViewWidth();
32289 h = Roo.lib.Dom.getViewHeight();
32292 this.viewSize = [w, h];
32293 if(this.modal && this.mask.isVisible()){
32294 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32295 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32297 if(this.isVisible()){
32298 this.constrainXY();
32303 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32304 * shadow, proxy, mask, etc.) Also removes all event listeners.
32305 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32307 destroy : function(removeEl){
32308 if(this.isVisible()){
32309 this.animateTarget = null;
32312 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32314 this.tabs.destroy(removeEl);
32327 for(var i = 0, len = this.buttons.length; i < len; i++){
32328 this.buttons[i].destroy();
32331 this.el.removeAllListeners();
32332 if(removeEl === true){
32333 this.el.update("");
32336 Roo.DialogManager.unregister(this);
32340 startMove : function(){
32341 if(this.proxyDrag){
32344 if(this.constraintoviewport !== false){
32345 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32350 endMove : function(){
32351 if(!this.proxyDrag){
32352 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32354 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32357 this.refreshSize();
32358 this.adjustAssets();
32360 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32364 * Brings this dialog to the front of any other visible dialogs
32365 * @return {Roo.BasicDialog} this
32367 toFront : function(){
32368 Roo.DialogManager.bringToFront(this);
32373 * Sends this dialog to the back (under) of any other visible dialogs
32374 * @return {Roo.BasicDialog} this
32376 toBack : function(){
32377 Roo.DialogManager.sendToBack(this);
32382 * Centers this dialog in the viewport
32383 * @return {Roo.BasicDialog} this
32385 center : function(){
32386 var xy = this.el.getCenterXY(true);
32387 this.moveTo(xy[0], xy[1]);
32392 * Moves the dialog's top-left corner to the specified point
32393 * @param {Number} x
32394 * @param {Number} y
32395 * @return {Roo.BasicDialog} this
32397 moveTo : function(x, y){
32399 if(this.isVisible()){
32400 this.el.setXY(this.xy);
32401 this.adjustAssets();
32407 * Aligns the dialog to the specified element
32408 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32409 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32410 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32411 * @return {Roo.BasicDialog} this
32413 alignTo : function(element, position, offsets){
32414 this.xy = this.el.getAlignToXY(element, position, offsets);
32415 if(this.isVisible()){
32416 this.el.setXY(this.xy);
32417 this.adjustAssets();
32423 * Anchors an element to another element and realigns it when the window is resized.
32424 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32425 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32426 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32427 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32428 * is a number, it is used as the buffer delay (defaults to 50ms).
32429 * @return {Roo.BasicDialog} this
32431 anchorTo : function(el, alignment, offsets, monitorScroll){
32432 var action = function(){
32433 this.alignTo(el, alignment, offsets);
32435 Roo.EventManager.onWindowResize(action, this);
32436 var tm = typeof monitorScroll;
32437 if(tm != 'undefined'){
32438 Roo.EventManager.on(window, 'scroll', action, this,
32439 {buffer: tm == 'number' ? monitorScroll : 50});
32446 * Returns true if the dialog is visible
32447 * @return {Boolean}
32449 isVisible : function(){
32450 return this.el.isVisible();
32454 animHide : function(callback){
32455 var b = Roo.get(this.animateTarget).getBox();
32457 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32459 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32460 this.hideEl.createDelegate(this, [callback]));
32464 * Hides the dialog.
32465 * @param {Function} callback (optional) Function to call when the dialog is hidden
32466 * @return {Roo.BasicDialog} this
32468 hide : function(callback){
32469 if (this.fireEvent("beforehide", this) === false){
32473 this.shadow.hide();
32478 // sometimes animateTarget seems to get set.. causing problems...
32479 // this just double checks..
32480 if(this.animateTarget && Roo.get(this.animateTarget)) {
32481 this.animHide(callback);
32484 this.hideEl(callback);
32490 hideEl : function(callback){
32494 Roo.get(document.body).removeClass("x-body-masked");
32496 this.fireEvent("hide", this);
32497 if(typeof callback == "function"){
32503 hideAction : function(){
32504 this.setLeft("-10000px");
32505 this.setTop("-10000px");
32506 this.setStyle("visibility", "hidden");
32510 refreshSize : function(){
32511 this.size = this.el.getSize();
32512 this.xy = this.el.getXY();
32513 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32517 // z-index is managed by the DialogManager and may be overwritten at any time
32518 setZIndex : function(index){
32520 this.mask.setStyle("z-index", index);
32523 this.shim.setStyle("z-index", ++index);
32526 this.shadow.setZIndex(++index);
32528 this.el.setStyle("z-index", ++index);
32530 this.proxy.setStyle("z-index", ++index);
32533 this.resizer.proxy.setStyle("z-index", ++index);
32536 this.lastZIndex = index;
32540 * Returns the element for this dialog
32541 * @return {Roo.Element} The underlying dialog Element
32543 getEl : function(){
32549 * @class Roo.DialogManager
32550 * Provides global access to BasicDialogs that have been created and
32551 * support for z-indexing (layering) multiple open dialogs.
32553 Roo.DialogManager = function(){
32555 var accessList = [];
32559 var sortDialogs = function(d1, d2){
32560 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32564 var orderDialogs = function(){
32565 accessList.sort(sortDialogs);
32566 var seed = Roo.DialogManager.zseed;
32567 for(var i = 0, len = accessList.length; i < len; i++){
32568 var dlg = accessList[i];
32570 dlg.setZIndex(seed + (i*10));
32577 * The starting z-index for BasicDialogs (defaults to 9000)
32578 * @type Number The z-index value
32583 register : function(dlg){
32584 list[dlg.id] = dlg;
32585 accessList.push(dlg);
32589 unregister : function(dlg){
32590 delete list[dlg.id];
32593 if(!accessList.indexOf){
32594 for( i = 0, len = accessList.length; i < len; i++){
32595 if(accessList[i] == dlg){
32596 accessList.splice(i, 1);
32601 i = accessList.indexOf(dlg);
32603 accessList.splice(i, 1);
32609 * Gets a registered dialog by id
32610 * @param {String/Object} id The id of the dialog or a dialog
32611 * @return {Roo.BasicDialog} this
32613 get : function(id){
32614 return typeof id == "object" ? id : list[id];
32618 * Brings the specified dialog to the front
32619 * @param {String/Object} dlg The id of the dialog or a dialog
32620 * @return {Roo.BasicDialog} this
32622 bringToFront : function(dlg){
32623 dlg = this.get(dlg);
32626 dlg._lastAccess = new Date().getTime();
32633 * Sends the specified dialog to the back
32634 * @param {String/Object} dlg The id of the dialog or a dialog
32635 * @return {Roo.BasicDialog} this
32637 sendToBack : function(dlg){
32638 dlg = this.get(dlg);
32639 dlg._lastAccess = -(new Date().getTime());
32645 * Hides all dialogs
32647 hideAll : function(){
32648 for(var id in list){
32649 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32658 * @class Roo.LayoutDialog
32659 * @extends Roo.BasicDialog
32660 * Dialog which provides adjustments for working with a layout in a Dialog.
32661 * Add your necessary layout config options to the dialog's config.<br>
32662 * Example usage (including a nested layout):
32665 dialog = new Roo.LayoutDialog("download-dlg", {
32674 // layout config merges with the dialog config
32676 tabPosition: "top",
32677 alwaysShowTabs: true
32680 dialog.addKeyListener(27, dialog.hide, dialog);
32681 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32682 dialog.addButton("Build It!", this.getDownload, this);
32684 // we can even add nested layouts
32685 var innerLayout = new Roo.BorderLayout("dl-inner", {
32695 innerLayout.beginUpdate();
32696 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32697 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32698 innerLayout.endUpdate(true);
32700 var layout = dialog.getLayout();
32701 layout.beginUpdate();
32702 layout.add("center", new Roo.ContentPanel("standard-panel",
32703 {title: "Download the Source", fitToFrame:true}));
32704 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32705 {title: "Build your own roo.js"}));
32706 layout.getRegion("center").showPanel(sp);
32707 layout.endUpdate();
32711 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32712 * @param {Object} config configuration options
32714 Roo.LayoutDialog = function(el, cfg){
32717 if (typeof(cfg) == 'undefined') {
32718 config = Roo.apply({}, el);
32719 // not sure why we use documentElement here.. - it should always be body.
32720 // IE7 borks horribly if we use documentElement.
32721 // webkit also does not like documentElement - it creates a body element...
32722 el = Roo.get( document.body || document.documentElement ).createChild();
32723 //config.autoCreate = true;
32727 config.autoTabs = false;
32728 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32729 this.body.setStyle({overflow:"hidden", position:"relative"});
32730 this.layout = new Roo.BorderLayout(this.body.dom, config);
32731 this.layout.monitorWindowResize = false;
32732 this.el.addClass("x-dlg-auto-layout");
32733 // fix case when center region overwrites center function
32734 this.center = Roo.BasicDialog.prototype.center;
32735 this.on("show", this.layout.layout, this.layout, true);
32736 if (config.items) {
32737 var xitems = config.items;
32738 delete config.items;
32739 Roo.each(xitems, this.addxtype, this);
32744 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32746 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32749 endUpdate : function(){
32750 this.layout.endUpdate();
32754 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32757 beginUpdate : function(){
32758 this.layout.beginUpdate();
32762 * Get the BorderLayout for this dialog
32763 * @return {Roo.BorderLayout}
32765 getLayout : function(){
32766 return this.layout;
32769 showEl : function(){
32770 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32772 this.layout.layout();
32777 // Use the syncHeightBeforeShow config option to control this automatically
32778 syncBodyHeight : function(){
32779 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32780 if(this.layout){this.layout.layout();}
32784 * Add an xtype element (actually adds to the layout.)
32785 * @return {Object} xdata xtype object data.
32788 addxtype : function(c) {
32789 return this.layout.addxtype(c);
32793 * Ext JS Library 1.1.1
32794 * Copyright(c) 2006-2007, Ext JS, LLC.
32796 * Originally Released Under LGPL - original licence link has changed is not relivant.
32799 * <script type="text/javascript">
32803 * @class Roo.MessageBox
32804 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32808 Roo.Msg.alert('Status', 'Changes saved successfully.');
32810 // Prompt for user data:
32811 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32813 // process text value...
32817 // Show a dialog using config options:
32819 title:'Save Changes?',
32820 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32821 buttons: Roo.Msg.YESNOCANCEL,
32828 Roo.MessageBox = function(){
32829 var dlg, opt, mask, waitTimer;
32830 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32831 var buttons, activeTextEl, bwidth;
32834 var handleButton = function(button){
32836 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32840 var handleHide = function(){
32841 if(opt && opt.cls){
32842 dlg.el.removeClass(opt.cls);
32845 Roo.TaskMgr.stop(waitTimer);
32851 var updateButtons = function(b){
32854 buttons["ok"].hide();
32855 buttons["cancel"].hide();
32856 buttons["yes"].hide();
32857 buttons["no"].hide();
32858 dlg.footer.dom.style.display = 'none';
32861 dlg.footer.dom.style.display = '';
32862 for(var k in buttons){
32863 if(typeof buttons[k] != "function"){
32866 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
32867 width += buttons[k].el.getWidth()+15;
32877 var handleEsc = function(d, k, e){
32878 if(opt && opt.closable !== false){
32888 * Returns a reference to the underlying {@link Roo.BasicDialog} element
32889 * @return {Roo.BasicDialog} The BasicDialog element
32891 getDialog : function(){
32893 dlg = new Roo.BasicDialog("x-msg-box", {
32898 constraintoviewport:false,
32900 collapsible : false,
32903 width:400, height:100,
32904 buttonAlign:"center",
32905 closeClick : function(){
32906 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
32907 handleButton("no");
32909 handleButton("cancel");
32913 dlg.on("hide", handleHide);
32915 dlg.addKeyListener(27, handleEsc);
32917 var bt = this.buttonText;
32918 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
32919 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
32920 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
32921 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
32922 bodyEl = dlg.body.createChild({
32924 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>'
32926 msgEl = bodyEl.dom.firstChild;
32927 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
32928 textboxEl.enableDisplayMode();
32929 textboxEl.addKeyListener([10,13], function(){
32930 if(dlg.isVisible() && opt && opt.buttons){
32931 if(opt.buttons.ok){
32932 handleButton("ok");
32933 }else if(opt.buttons.yes){
32934 handleButton("yes");
32938 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
32939 textareaEl.enableDisplayMode();
32940 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
32941 progressEl.enableDisplayMode();
32942 var pf = progressEl.dom.firstChild;
32944 pp = Roo.get(pf.firstChild);
32945 pp.setHeight(pf.offsetHeight);
32953 * Updates the message box body text
32954 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
32955 * the XHTML-compliant non-breaking space character '&#160;')
32956 * @return {Roo.MessageBox} This message box
32958 updateText : function(text){
32959 if(!dlg.isVisible() && !opt.width){
32960 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
32962 msgEl.innerHTML = text || ' ';
32964 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
32965 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
32967 Math.min(opt.width || cw , this.maxWidth),
32968 Math.max(opt.minWidth || this.minWidth, bwidth)
32971 activeTextEl.setWidth(w);
32973 if(dlg.isVisible()){
32974 dlg.fixedcenter = false;
32976 // to big, make it scroll. = But as usual stupid IE does not support
32979 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
32980 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
32981 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
32983 bodyEl.dom.style.height = '';
32984 bodyEl.dom.style.overflowY = '';
32987 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
32989 bodyEl.dom.style.overflowX = '';
32992 dlg.setContentSize(w, bodyEl.getHeight());
32993 if(dlg.isVisible()){
32994 dlg.fixedcenter = true;
33000 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33001 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33002 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33003 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33004 * @return {Roo.MessageBox} This message box
33006 updateProgress : function(value, text){
33008 this.updateText(text);
33010 if (pp) { // weird bug on my firefox - for some reason this is not defined
33011 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33017 * Returns true if the message box is currently displayed
33018 * @return {Boolean} True if the message box is visible, else false
33020 isVisible : function(){
33021 return dlg && dlg.isVisible();
33025 * Hides the message box if it is displayed
33028 if(this.isVisible()){
33034 * Displays a new message box, or reinitializes an existing message box, based on the config options
33035 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33036 * The following config object properties are supported:
33038 Property Type Description
33039 ---------- --------------- ------------------------------------------------------------------------------------
33040 animEl String/Element An id or Element from which the message box should animate as it opens and
33041 closes (defaults to undefined)
33042 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33043 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33044 closable Boolean False to hide the top-right close button (defaults to true). Note that
33045 progress and wait dialogs will ignore this property and always hide the
33046 close button as they can only be closed programmatically.
33047 cls String A custom CSS class to apply to the message box element
33048 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33049 displayed (defaults to 75)
33050 fn Function A callback function to execute after closing the dialog. The arguments to the
33051 function will be btn (the name of the button that was clicked, if applicable,
33052 e.g. "ok"), and text (the value of the active text field, if applicable).
33053 Progress and wait dialogs will ignore this option since they do not respond to
33054 user actions and can only be closed programmatically, so any required function
33055 should be called by the same code after it closes the dialog.
33056 icon String A CSS class that provides a background image to be used as an icon for
33057 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33058 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33059 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33060 modal Boolean False to allow user interaction with the page while the message box is
33061 displayed (defaults to true)
33062 msg String A string that will replace the existing message box body text (defaults
33063 to the XHTML-compliant non-breaking space character ' ')
33064 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33065 progress Boolean True to display a progress bar (defaults to false)
33066 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33067 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33068 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33069 title String The title text
33070 value String The string value to set into the active textbox element if displayed
33071 wait Boolean True to display a progress bar (defaults to false)
33072 width Number The width of the dialog in pixels
33079 msg: 'Please enter your address:',
33081 buttons: Roo.MessageBox.OKCANCEL,
33084 animEl: 'addAddressBtn'
33087 * @param {Object} config Configuration options
33088 * @return {Roo.MessageBox} This message box
33090 show : function(options)
33093 // this causes nightmares if you show one dialog after another
33094 // especially on callbacks..
33096 if(this.isVisible()){
33099 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33100 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33101 Roo.log("New Dialog Message:" + options.msg )
33102 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33103 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33106 var d = this.getDialog();
33108 d.setTitle(opt.title || " ");
33109 d.close.setDisplayed(opt.closable !== false);
33110 activeTextEl = textboxEl;
33111 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33116 textareaEl.setHeight(typeof opt.multiline == "number" ?
33117 opt.multiline : this.defaultTextHeight);
33118 activeTextEl = textareaEl;
33127 progressEl.setDisplayed(opt.progress === true);
33128 this.updateProgress(0);
33129 activeTextEl.dom.value = opt.value || "";
33131 dlg.setDefaultButton(activeTextEl);
33133 var bs = opt.buttons;
33136 db = buttons["ok"];
33137 }else if(bs && bs.yes){
33138 db = buttons["yes"];
33140 dlg.setDefaultButton(db);
33142 bwidth = updateButtons(opt.buttons);
33143 this.updateText(opt.msg);
33145 d.el.addClass(opt.cls);
33147 d.proxyDrag = opt.proxyDrag === true;
33148 d.modal = opt.modal !== false;
33149 d.mask = opt.modal !== false ? mask : false;
33150 if(!d.isVisible()){
33151 // force it to the end of the z-index stack so it gets a cursor in FF
33152 document.body.appendChild(dlg.el.dom);
33153 d.animateTarget = null;
33154 d.show(options.animEl);
33160 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33161 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33162 * and closing the message box when the process is complete.
33163 * @param {String} title The title bar text
33164 * @param {String} msg The message box body text
33165 * @return {Roo.MessageBox} This message box
33167 progress : function(title, msg){
33174 minWidth: this.minProgressWidth,
33181 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33182 * If a callback function is passed it will be called after the user clicks the button, and the
33183 * id of the button that was clicked will be passed as the only parameter to the callback
33184 * (could also be the top-right close button).
33185 * @param {String} title The title bar text
33186 * @param {String} msg The message box body text
33187 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33188 * @param {Object} scope (optional) The scope of the callback function
33189 * @return {Roo.MessageBox} This message box
33191 alert : function(title, msg, fn, scope){
33204 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33205 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33206 * You are responsible for closing the message box when the process is complete.
33207 * @param {String} msg The message box body text
33208 * @param {String} title (optional) The title bar text
33209 * @return {Roo.MessageBox} This message box
33211 wait : function(msg, title){
33222 waitTimer = Roo.TaskMgr.start({
33224 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33232 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33233 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33234 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33235 * @param {String} title The title bar text
33236 * @param {String} msg The message box body text
33237 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33238 * @param {Object} scope (optional) The scope of the callback function
33239 * @return {Roo.MessageBox} This message box
33241 confirm : function(title, msg, fn, scope){
33245 buttons: this.YESNO,
33254 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33255 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33256 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33257 * (could also be the top-right close button) and the text that was entered will be passed as the two
33258 * parameters to the callback.
33259 * @param {String} title The title bar text
33260 * @param {String} msg The message box body text
33261 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33262 * @param {Object} scope (optional) The scope of the callback function
33263 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33264 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33265 * @return {Roo.MessageBox} This message box
33267 prompt : function(title, msg, fn, scope, multiline){
33271 buttons: this.OKCANCEL,
33276 multiline: multiline,
33283 * Button config that displays a single OK button
33288 * Button config that displays Yes and No buttons
33291 YESNO : {yes:true, no:true},
33293 * Button config that displays OK and Cancel buttons
33296 OKCANCEL : {ok:true, cancel:true},
33298 * Button config that displays Yes, No and Cancel buttons
33301 YESNOCANCEL : {yes:true, no:true, cancel:true},
33304 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33307 defaultTextHeight : 75,
33309 * The maximum width in pixels of the message box (defaults to 600)
33314 * The minimum width in pixels of the message box (defaults to 100)
33319 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33320 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33323 minProgressWidth : 250,
33325 * An object containing the default button text strings that can be overriden for localized language support.
33326 * Supported properties are: ok, cancel, yes and no.
33327 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33340 * Shorthand for {@link Roo.MessageBox}
33342 Roo.Msg = Roo.MessageBox;/*
33344 * Ext JS Library 1.1.1
33345 * Copyright(c) 2006-2007, Ext JS, LLC.
33347 * Originally Released Under LGPL - original licence link has changed is not relivant.
33350 * <script type="text/javascript">
33353 * @class Roo.QuickTips
33354 * Provides attractive and customizable tooltips for any element.
33357 Roo.QuickTips = function(){
33358 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33359 var ce, bd, xy, dd;
33360 var visible = false, disabled = true, inited = false;
33361 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33363 var onOver = function(e){
33367 var t = e.getTarget();
33368 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33371 if(ce && t == ce.el){
33372 clearTimeout(hideProc);
33375 if(t && tagEls[t.id]){
33376 tagEls[t.id].el = t;
33377 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33380 var ttp, et = Roo.fly(t);
33381 var ns = cfg.namespace;
33382 if(tm.interceptTitles && t.title){
33385 t.removeAttribute("title");
33386 e.preventDefault();
33388 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33391 showProc = show.defer(tm.showDelay, tm, [{
33394 width: et.getAttributeNS(ns, cfg.width),
33395 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33396 title: et.getAttributeNS(ns, cfg.title),
33397 cls: et.getAttributeNS(ns, cfg.cls)
33402 var onOut = function(e){
33403 clearTimeout(showProc);
33404 var t = e.getTarget();
33405 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33406 hideProc = setTimeout(hide, tm.hideDelay);
33410 var onMove = function(e){
33416 if(tm.trackMouse && ce){
33421 var onDown = function(e){
33422 clearTimeout(showProc);
33423 clearTimeout(hideProc);
33425 if(tm.hideOnClick){
33428 tm.enable.defer(100, tm);
33433 var getPad = function(){
33434 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33437 var show = function(o){
33441 clearTimeout(dismissProc);
33443 if(removeCls){ // in case manually hidden
33444 el.removeClass(removeCls);
33448 el.addClass(ce.cls);
33449 removeCls = ce.cls;
33452 tipTitle.update(ce.title);
33455 tipTitle.update('');
33458 el.dom.style.width = tm.maxWidth+'px';
33459 //tipBody.dom.style.width = '';
33460 tipBodyText.update(o.text);
33461 var p = getPad(), w = ce.width;
33463 var td = tipBodyText.dom;
33464 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33465 if(aw > tm.maxWidth){
33467 }else if(aw < tm.minWidth){
33473 //tipBody.setWidth(w);
33474 el.setWidth(parseInt(w, 10) + p);
33475 if(ce.autoHide === false){
33476 close.setDisplayed(true);
33481 close.setDisplayed(false);
33487 el.avoidY = xy[1]-18;
33492 el.setStyle("visibility", "visible");
33493 el.fadeIn({callback: afterShow});
33499 var afterShow = function(){
33503 if(tm.autoDismiss && ce.autoHide !== false){
33504 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33509 var hide = function(noanim){
33510 clearTimeout(dismissProc);
33511 clearTimeout(hideProc);
33513 if(el.isVisible()){
33515 if(noanim !== true && tm.animate){
33516 el.fadeOut({callback: afterHide});
33523 var afterHide = function(){
33526 el.removeClass(removeCls);
33533 * @cfg {Number} minWidth
33534 * The minimum width of the quick tip (defaults to 40)
33538 * @cfg {Number} maxWidth
33539 * The maximum width of the quick tip (defaults to 300)
33543 * @cfg {Boolean} interceptTitles
33544 * True to automatically use the element's DOM title value if available (defaults to false)
33546 interceptTitles : false,
33548 * @cfg {Boolean} trackMouse
33549 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33551 trackMouse : false,
33553 * @cfg {Boolean} hideOnClick
33554 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33556 hideOnClick : true,
33558 * @cfg {Number} showDelay
33559 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33563 * @cfg {Number} hideDelay
33564 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33568 * @cfg {Boolean} autoHide
33569 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33570 * Used in conjunction with hideDelay.
33575 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33576 * (defaults to true). Used in conjunction with autoDismissDelay.
33578 autoDismiss : true,
33581 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33583 autoDismissDelay : 5000,
33585 * @cfg {Boolean} animate
33586 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33591 * @cfg {String} title
33592 * Title text to display (defaults to ''). This can be any valid HTML markup.
33596 * @cfg {String} text
33597 * Body text to display (defaults to ''). This can be any valid HTML markup.
33601 * @cfg {String} cls
33602 * A CSS class to apply to the base quick tip element (defaults to '').
33606 * @cfg {Number} width
33607 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33608 * minWidth or maxWidth.
33613 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33614 * or display QuickTips in a page.
33617 tm = Roo.QuickTips;
33618 cfg = tm.tagConfig;
33620 if(!Roo.isReady){ // allow calling of init() before onReady
33621 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33624 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33625 el.fxDefaults = {stopFx: true};
33626 // maximum custom styling
33627 //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>');
33628 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>');
33629 tipTitle = el.child('h3');
33630 tipTitle.enableDisplayMode("block");
33631 tipBody = el.child('div.x-tip-bd');
33632 tipBodyText = el.child('div.x-tip-bd-inner');
33633 //bdLeft = el.child('div.x-tip-bd-left');
33634 //bdRight = el.child('div.x-tip-bd-right');
33635 close = el.child('div.x-tip-close');
33636 close.enableDisplayMode("block");
33637 close.on("click", hide);
33638 var d = Roo.get(document);
33639 d.on("mousedown", onDown);
33640 d.on("mouseover", onOver);
33641 d.on("mouseout", onOut);
33642 d.on("mousemove", onMove);
33643 esc = d.addKeyListener(27, hide);
33646 dd = el.initDD("default", null, {
33647 onDrag : function(){
33651 dd.setHandleElId(tipTitle.id);
33660 * Configures a new quick tip instance and assigns it to a target element. The following config options
33663 Property Type Description
33664 ---------- --------------------- ------------------------------------------------------------------------
33665 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33667 * @param {Object} config The config object
33669 register : function(config){
33670 var cs = config instanceof Array ? config : arguments;
33671 for(var i = 0, len = cs.length; i < len; i++) {
33673 var target = c.target;
33675 if(target instanceof Array){
33676 for(var j = 0, jlen = target.length; j < jlen; j++){
33677 tagEls[target[j]] = c;
33680 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33687 * Removes this quick tip from its element and destroys it.
33688 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33690 unregister : function(el){
33691 delete tagEls[Roo.id(el)];
33695 * Enable this quick tip.
33697 enable : function(){
33698 if(inited && disabled){
33700 if(locks.length < 1){
33707 * Disable this quick tip.
33709 disable : function(){
33711 clearTimeout(showProc);
33712 clearTimeout(hideProc);
33713 clearTimeout(dismissProc);
33721 * Returns true if the quick tip is enabled, else false.
33723 isEnabled : function(){
33729 namespace : "roo", // was ext?? this may break..
33730 alt_namespace : "ext",
33731 attribute : "qtip",
33741 // backwards compat
33742 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33744 * Ext JS Library 1.1.1
33745 * Copyright(c) 2006-2007, Ext JS, LLC.
33747 * Originally Released Under LGPL - original licence link has changed is not relivant.
33750 * <script type="text/javascript">
33755 * @class Roo.tree.TreePanel
33756 * @extends Roo.data.Tree
33758 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33759 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33760 * @cfg {Boolean} enableDD true to enable drag and drop
33761 * @cfg {Boolean} enableDrag true to enable just drag
33762 * @cfg {Boolean} enableDrop true to enable just drop
33763 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33764 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33765 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33766 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33767 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33768 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33769 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33770 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33771 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33772 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33773 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33774 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33775 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33776 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33777 * @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>
33778 * @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>
33781 * @param {String/HTMLElement/Element} el The container element
33782 * @param {Object} config
33784 Roo.tree.TreePanel = function(el, config){
33786 var loader = false;
33788 root = config.root;
33789 delete config.root;
33791 if (config.loader) {
33792 loader = config.loader;
33793 delete config.loader;
33796 Roo.apply(this, config);
33797 Roo.tree.TreePanel.superclass.constructor.call(this);
33798 this.el = Roo.get(el);
33799 this.el.addClass('x-tree');
33800 //console.log(root);
33802 this.setRootNode( Roo.factory(root, Roo.tree));
33805 this.loader = Roo.factory(loader, Roo.tree);
33808 * Read-only. The id of the container element becomes this TreePanel's id.
33810 this.id = this.el.id;
33813 * @event beforeload
33814 * Fires before a node is loaded, return false to cancel
33815 * @param {Node} node The node being loaded
33817 "beforeload" : true,
33820 * Fires when a node is loaded
33821 * @param {Node} node The node that was loaded
33825 * @event textchange
33826 * Fires when the text for a node is changed
33827 * @param {Node} node The node
33828 * @param {String} text The new text
33829 * @param {String} oldText The old text
33831 "textchange" : true,
33833 * @event beforeexpand
33834 * Fires before a node is expanded, return false to cancel.
33835 * @param {Node} node The node
33836 * @param {Boolean} deep
33837 * @param {Boolean} anim
33839 "beforeexpand" : true,
33841 * @event beforecollapse
33842 * Fires before a node is collapsed, return false to cancel.
33843 * @param {Node} node The node
33844 * @param {Boolean} deep
33845 * @param {Boolean} anim
33847 "beforecollapse" : true,
33850 * Fires when a node is expanded
33851 * @param {Node} node The node
33855 * @event disabledchange
33856 * Fires when the disabled status of a node changes
33857 * @param {Node} node The node
33858 * @param {Boolean} disabled
33860 "disabledchange" : true,
33863 * Fires when a node is collapsed
33864 * @param {Node} node The node
33868 * @event beforeclick
33869 * Fires before click processing on a node. Return false to cancel the default action.
33870 * @param {Node} node The node
33871 * @param {Roo.EventObject} e The event object
33873 "beforeclick":true,
33875 * @event checkchange
33876 * Fires when a node with a checkbox's checked property changes
33877 * @param {Node} this This node
33878 * @param {Boolean} checked
33880 "checkchange":true,
33883 * Fires when a node is clicked
33884 * @param {Node} node The node
33885 * @param {Roo.EventObject} e The event object
33890 * Fires when a node is double clicked
33891 * @param {Node} node The node
33892 * @param {Roo.EventObject} e The event object
33896 * @event contextmenu
33897 * Fires when a node is right clicked
33898 * @param {Node} node The node
33899 * @param {Roo.EventObject} e The event object
33901 "contextmenu":true,
33903 * @event beforechildrenrendered
33904 * Fires right before the child nodes for a node are rendered
33905 * @param {Node} node The node
33907 "beforechildrenrendered":true,
33910 * Fires when a node starts being dragged
33911 * @param {Roo.tree.TreePanel} this
33912 * @param {Roo.tree.TreeNode} node
33913 * @param {event} e The raw browser event
33915 "startdrag" : true,
33918 * Fires when a drag operation is complete
33919 * @param {Roo.tree.TreePanel} this
33920 * @param {Roo.tree.TreeNode} node
33921 * @param {event} e The raw browser event
33926 * Fires when a dragged node is dropped on a valid DD target
33927 * @param {Roo.tree.TreePanel} this
33928 * @param {Roo.tree.TreeNode} node
33929 * @param {DD} dd The dd it was dropped on
33930 * @param {event} e The raw browser event
33934 * @event beforenodedrop
33935 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
33936 * passed to handlers has the following properties:<br />
33937 * <ul style="padding:5px;padding-left:16px;">
33938 * <li>tree - The TreePanel</li>
33939 * <li>target - The node being targeted for the drop</li>
33940 * <li>data - The drag data from the drag source</li>
33941 * <li>point - The point of the drop - append, above or below</li>
33942 * <li>source - The drag source</li>
33943 * <li>rawEvent - Raw mouse event</li>
33944 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
33945 * to be inserted by setting them on this object.</li>
33946 * <li>cancel - Set this to true to cancel the drop.</li>
33948 * @param {Object} dropEvent
33950 "beforenodedrop" : true,
33953 * Fires after a DD object is dropped on a node in this tree. The dropEvent
33954 * passed to handlers has the following properties:<br />
33955 * <ul style="padding:5px;padding-left:16px;">
33956 * <li>tree - The TreePanel</li>
33957 * <li>target - The node being targeted for the drop</li>
33958 * <li>data - The drag data from the drag source</li>
33959 * <li>point - The point of the drop - append, above or below</li>
33960 * <li>source - The drag source</li>
33961 * <li>rawEvent - Raw mouse event</li>
33962 * <li>dropNode - Dropped node(s).</li>
33964 * @param {Object} dropEvent
33968 * @event nodedragover
33969 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
33970 * passed to handlers has the following properties:<br />
33971 * <ul style="padding:5px;padding-left:16px;">
33972 * <li>tree - The TreePanel</li>
33973 * <li>target - The node being targeted for the drop</li>
33974 * <li>data - The drag data from the drag source</li>
33975 * <li>point - The point of the drop - append, above or below</li>
33976 * <li>source - The drag source</li>
33977 * <li>rawEvent - Raw mouse event</li>
33978 * <li>dropNode - Drop node(s) provided by the source.</li>
33979 * <li>cancel - Set this to true to signal drop not allowed.</li>
33981 * @param {Object} dragOverEvent
33983 "nodedragover" : true
33986 if(this.singleExpand){
33987 this.on("beforeexpand", this.restrictExpand, this);
33990 this.editor.tree = this;
33991 this.editor = Roo.factory(this.editor, Roo.tree);
33994 if (this.selModel) {
33995 this.selModel = Roo.factory(this.selModel, Roo.tree);
33999 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34000 rootVisible : true,
34001 animate: Roo.enableFx,
34004 hlDrop : Roo.enableFx,
34008 rendererTip: false,
34010 restrictExpand : function(node){
34011 var p = node.parentNode;
34013 if(p.expandedChild && p.expandedChild.parentNode == p){
34014 p.expandedChild.collapse();
34016 p.expandedChild = node;
34020 // private override
34021 setRootNode : function(node){
34022 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34023 if(!this.rootVisible){
34024 node.ui = new Roo.tree.RootTreeNodeUI(node);
34030 * Returns the container element for this TreePanel
34032 getEl : function(){
34037 * Returns the default TreeLoader for this TreePanel
34039 getLoader : function(){
34040 return this.loader;
34046 expandAll : function(){
34047 this.root.expand(true);
34051 * Collapse all nodes
34053 collapseAll : function(){
34054 this.root.collapse(true);
34058 * Returns the selection model used by this TreePanel
34060 getSelectionModel : function(){
34061 if(!this.selModel){
34062 this.selModel = new Roo.tree.DefaultSelectionModel();
34064 return this.selModel;
34068 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34069 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34070 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34073 getChecked : function(a, startNode){
34074 startNode = startNode || this.root;
34076 var f = function(){
34077 if(this.attributes.checked){
34078 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34081 startNode.cascade(f);
34086 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34087 * @param {String} path
34088 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34089 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34090 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34092 expandPath : function(path, attr, callback){
34093 attr = attr || "id";
34094 var keys = path.split(this.pathSeparator);
34095 var curNode = this.root;
34096 if(curNode.attributes[attr] != keys[1]){ // invalid root
34098 callback(false, null);
34103 var f = function(){
34104 if(++index == keys.length){
34106 callback(true, curNode);
34110 var c = curNode.findChild(attr, keys[index]);
34113 callback(false, curNode);
34118 c.expand(false, false, f);
34120 curNode.expand(false, false, f);
34124 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34125 * @param {String} path
34126 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34127 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34128 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34130 selectPath : function(path, attr, callback){
34131 attr = attr || "id";
34132 var keys = path.split(this.pathSeparator);
34133 var v = keys.pop();
34134 if(keys.length > 0){
34135 var f = function(success, node){
34136 if(success && node){
34137 var n = node.findChild(attr, v);
34143 }else if(callback){
34144 callback(false, n);
34148 callback(false, n);
34152 this.expandPath(keys.join(this.pathSeparator), attr, f);
34154 this.root.select();
34156 callback(true, this.root);
34161 getTreeEl : function(){
34166 * Trigger rendering of this TreePanel
34168 render : function(){
34169 if (this.innerCt) {
34170 return this; // stop it rendering more than once!!
34173 this.innerCt = this.el.createChild({tag:"ul",
34174 cls:"x-tree-root-ct " +
34175 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34177 if(this.containerScroll){
34178 Roo.dd.ScrollManager.register(this.el);
34180 if((this.enableDD || this.enableDrop) && !this.dropZone){
34182 * The dropZone used by this tree if drop is enabled
34183 * @type Roo.tree.TreeDropZone
34185 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34186 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34189 if((this.enableDD || this.enableDrag) && !this.dragZone){
34191 * The dragZone used by this tree if drag is enabled
34192 * @type Roo.tree.TreeDragZone
34194 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34195 ddGroup: this.ddGroup || "TreeDD",
34196 scroll: this.ddScroll
34199 this.getSelectionModel().init(this);
34201 Roo.log("ROOT not set in tree");
34204 this.root.render();
34205 if(!this.rootVisible){
34206 this.root.renderChildren();
34212 * Ext JS Library 1.1.1
34213 * Copyright(c) 2006-2007, Ext JS, LLC.
34215 * Originally Released Under LGPL - original licence link has changed is not relivant.
34218 * <script type="text/javascript">
34223 * @class Roo.tree.DefaultSelectionModel
34224 * @extends Roo.util.Observable
34225 * The default single selection for a TreePanel.
34226 * @param {Object} cfg Configuration
34228 Roo.tree.DefaultSelectionModel = function(cfg){
34229 this.selNode = null;
34235 * @event selectionchange
34236 * Fires when the selected node changes
34237 * @param {DefaultSelectionModel} this
34238 * @param {TreeNode} node the new selection
34240 "selectionchange" : true,
34243 * @event beforeselect
34244 * Fires before the selected node changes, return false to cancel the change
34245 * @param {DefaultSelectionModel} this
34246 * @param {TreeNode} node the new selection
34247 * @param {TreeNode} node the old selection
34249 "beforeselect" : true
34252 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34255 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34256 init : function(tree){
34258 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34259 tree.on("click", this.onNodeClick, this);
34262 onNodeClick : function(node, e){
34263 if (e.ctrlKey && this.selNode == node) {
34264 this.unselect(node);
34272 * @param {TreeNode} node The node to select
34273 * @return {TreeNode} The selected node
34275 select : function(node){
34276 var last = this.selNode;
34277 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34279 last.ui.onSelectedChange(false);
34281 this.selNode = node;
34282 node.ui.onSelectedChange(true);
34283 this.fireEvent("selectionchange", this, node, last);
34290 * @param {TreeNode} node The node to unselect
34292 unselect : function(node){
34293 if(this.selNode == node){
34294 this.clearSelections();
34299 * Clear all selections
34301 clearSelections : function(){
34302 var n = this.selNode;
34304 n.ui.onSelectedChange(false);
34305 this.selNode = null;
34306 this.fireEvent("selectionchange", this, null);
34312 * Get the selected node
34313 * @return {TreeNode} The selected node
34315 getSelectedNode : function(){
34316 return this.selNode;
34320 * Returns true if the node is selected
34321 * @param {TreeNode} node The node to check
34322 * @return {Boolean}
34324 isSelected : function(node){
34325 return this.selNode == node;
34329 * Selects the node above the selected node in the tree, intelligently walking the nodes
34330 * @return TreeNode The new selection
34332 selectPrevious : function(){
34333 var s = this.selNode || this.lastSelNode;
34337 var ps = s.previousSibling;
34339 if(!ps.isExpanded() || ps.childNodes.length < 1){
34340 return this.select(ps);
34342 var lc = ps.lastChild;
34343 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34346 return this.select(lc);
34348 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34349 return this.select(s.parentNode);
34355 * Selects the node above the selected node in the tree, intelligently walking the nodes
34356 * @return TreeNode The new selection
34358 selectNext : function(){
34359 var s = this.selNode || this.lastSelNode;
34363 if(s.firstChild && s.isExpanded()){
34364 return this.select(s.firstChild);
34365 }else if(s.nextSibling){
34366 return this.select(s.nextSibling);
34367 }else if(s.parentNode){
34369 s.parentNode.bubble(function(){
34370 if(this.nextSibling){
34371 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34380 onKeyDown : function(e){
34381 var s = this.selNode || this.lastSelNode;
34382 // undesirable, but required
34387 var k = e.getKey();
34395 this.selectPrevious();
34398 e.preventDefault();
34399 if(s.hasChildNodes()){
34400 if(!s.isExpanded()){
34402 }else if(s.firstChild){
34403 this.select(s.firstChild, e);
34408 e.preventDefault();
34409 if(s.hasChildNodes() && s.isExpanded()){
34411 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34412 this.select(s.parentNode, e);
34420 * @class Roo.tree.MultiSelectionModel
34421 * @extends Roo.util.Observable
34422 * Multi selection for a TreePanel.
34423 * @param {Object} cfg Configuration
34425 Roo.tree.MultiSelectionModel = function(){
34426 this.selNodes = [];
34430 * @event selectionchange
34431 * Fires when the selected nodes change
34432 * @param {MultiSelectionModel} this
34433 * @param {Array} nodes Array of the selected nodes
34435 "selectionchange" : true
34437 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34441 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34442 init : function(tree){
34444 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34445 tree.on("click", this.onNodeClick, this);
34448 onNodeClick : function(node, e){
34449 this.select(node, e, e.ctrlKey);
34454 * @param {TreeNode} node The node to select
34455 * @param {EventObject} e (optional) An event associated with the selection
34456 * @param {Boolean} keepExisting True to retain existing selections
34457 * @return {TreeNode} The selected node
34459 select : function(node, e, keepExisting){
34460 if(keepExisting !== true){
34461 this.clearSelections(true);
34463 if(this.isSelected(node)){
34464 this.lastSelNode = node;
34467 this.selNodes.push(node);
34468 this.selMap[node.id] = node;
34469 this.lastSelNode = node;
34470 node.ui.onSelectedChange(true);
34471 this.fireEvent("selectionchange", this, this.selNodes);
34477 * @param {TreeNode} node The node to unselect
34479 unselect : function(node){
34480 if(this.selMap[node.id]){
34481 node.ui.onSelectedChange(false);
34482 var sn = this.selNodes;
34485 index = sn.indexOf(node);
34487 for(var i = 0, len = sn.length; i < len; i++){
34495 this.selNodes.splice(index, 1);
34497 delete this.selMap[node.id];
34498 this.fireEvent("selectionchange", this, this.selNodes);
34503 * Clear all selections
34505 clearSelections : function(suppressEvent){
34506 var sn = this.selNodes;
34508 for(var i = 0, len = sn.length; i < len; i++){
34509 sn[i].ui.onSelectedChange(false);
34511 this.selNodes = [];
34513 if(suppressEvent !== true){
34514 this.fireEvent("selectionchange", this, this.selNodes);
34520 * Returns true if the node is selected
34521 * @param {TreeNode} node The node to check
34522 * @return {Boolean}
34524 isSelected : function(node){
34525 return this.selMap[node.id] ? true : false;
34529 * Returns an array of the selected nodes
34532 getSelectedNodes : function(){
34533 return this.selNodes;
34536 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34538 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34540 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34543 * Ext JS Library 1.1.1
34544 * Copyright(c) 2006-2007, Ext JS, LLC.
34546 * Originally Released Under LGPL - original licence link has changed is not relivant.
34549 * <script type="text/javascript">
34553 * @class Roo.tree.TreeNode
34554 * @extends Roo.data.Node
34555 * @cfg {String} text The text for this node
34556 * @cfg {Boolean} expanded true to start the node expanded
34557 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34558 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34559 * @cfg {Boolean} disabled true to start the node disabled
34560 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34561 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34562 * @cfg {String} cls A css class to be added to the node
34563 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34564 * @cfg {String} href URL of the link used for the node (defaults to #)
34565 * @cfg {String} hrefTarget target frame for the link
34566 * @cfg {String} qtip An Ext QuickTip for the node
34567 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34568 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34569 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34570 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34571 * (defaults to undefined with no checkbox rendered)
34573 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34575 Roo.tree.TreeNode = function(attributes){
34576 attributes = attributes || {};
34577 if(typeof attributes == "string"){
34578 attributes = {text: attributes};
34580 this.childrenRendered = false;
34581 this.rendered = false;
34582 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34583 this.expanded = attributes.expanded === true;
34584 this.isTarget = attributes.isTarget !== false;
34585 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34586 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34589 * Read-only. The text for this node. To change it use setText().
34592 this.text = attributes.text;
34594 * True if this node is disabled.
34597 this.disabled = attributes.disabled === true;
34601 * @event textchange
34602 * Fires when the text for this node is changed
34603 * @param {Node} this This node
34604 * @param {String} text The new text
34605 * @param {String} oldText The old text
34607 "textchange" : true,
34609 * @event beforeexpand
34610 * Fires before this node is expanded, return false to cancel.
34611 * @param {Node} this This node
34612 * @param {Boolean} deep
34613 * @param {Boolean} anim
34615 "beforeexpand" : true,
34617 * @event beforecollapse
34618 * Fires before this node is collapsed, return false to cancel.
34619 * @param {Node} this This node
34620 * @param {Boolean} deep
34621 * @param {Boolean} anim
34623 "beforecollapse" : true,
34626 * Fires when this node is expanded
34627 * @param {Node} this This node
34631 * @event disabledchange
34632 * Fires when the disabled status of this node changes
34633 * @param {Node} this This node
34634 * @param {Boolean} disabled
34636 "disabledchange" : true,
34639 * Fires when this node is collapsed
34640 * @param {Node} this This node
34644 * @event beforeclick
34645 * Fires before click processing. Return false to cancel the default action.
34646 * @param {Node} this This node
34647 * @param {Roo.EventObject} e The event object
34649 "beforeclick":true,
34651 * @event checkchange
34652 * Fires when a node with a checkbox's checked property changes
34653 * @param {Node} this This node
34654 * @param {Boolean} checked
34656 "checkchange":true,
34659 * Fires when this node is clicked
34660 * @param {Node} this This node
34661 * @param {Roo.EventObject} e The event object
34666 * Fires when this node is double clicked
34667 * @param {Node} this This node
34668 * @param {Roo.EventObject} e The event object
34672 * @event contextmenu
34673 * Fires when this node is right clicked
34674 * @param {Node} this This node
34675 * @param {Roo.EventObject} e The event object
34677 "contextmenu":true,
34679 * @event beforechildrenrendered
34680 * Fires right before the child nodes for this node are rendered
34681 * @param {Node} this This node
34683 "beforechildrenrendered":true
34686 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34689 * Read-only. The UI for this node
34692 this.ui = new uiClass(this);
34694 // finally support items[]
34695 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34700 Roo.each(this.attributes.items, function(c) {
34701 this.appendChild(Roo.factory(c,Roo.Tree));
34703 delete this.attributes.items;
34708 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34709 preventHScroll: true,
34711 * Returns true if this node is expanded
34712 * @return {Boolean}
34714 isExpanded : function(){
34715 return this.expanded;
34719 * Returns the UI object for this node
34720 * @return {TreeNodeUI}
34722 getUI : function(){
34726 // private override
34727 setFirstChild : function(node){
34728 var of = this.firstChild;
34729 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34730 if(this.childrenRendered && of && node != of){
34731 of.renderIndent(true, true);
34734 this.renderIndent(true, true);
34738 // private override
34739 setLastChild : function(node){
34740 var ol = this.lastChild;
34741 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34742 if(this.childrenRendered && ol && node != ol){
34743 ol.renderIndent(true, true);
34746 this.renderIndent(true, true);
34750 // these methods are overridden to provide lazy rendering support
34751 // private override
34752 appendChild : function()
34754 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34755 if(node && this.childrenRendered){
34758 this.ui.updateExpandIcon();
34762 // private override
34763 removeChild : function(node){
34764 this.ownerTree.getSelectionModel().unselect(node);
34765 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34766 // if it's been rendered remove dom node
34767 if(this.childrenRendered){
34770 if(this.childNodes.length < 1){
34771 this.collapse(false, false);
34773 this.ui.updateExpandIcon();
34775 if(!this.firstChild) {
34776 this.childrenRendered = false;
34781 // private override
34782 insertBefore : function(node, refNode){
34783 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34784 if(newNode && refNode && this.childrenRendered){
34787 this.ui.updateExpandIcon();
34792 * Sets the text for this node
34793 * @param {String} text
34795 setText : function(text){
34796 var oldText = this.text;
34798 this.attributes.text = text;
34799 if(this.rendered){ // event without subscribing
34800 this.ui.onTextChange(this, text, oldText);
34802 this.fireEvent("textchange", this, text, oldText);
34806 * Triggers selection of this node
34808 select : function(){
34809 this.getOwnerTree().getSelectionModel().select(this);
34813 * Triggers deselection of this node
34815 unselect : function(){
34816 this.getOwnerTree().getSelectionModel().unselect(this);
34820 * Returns true if this node is selected
34821 * @return {Boolean}
34823 isSelected : function(){
34824 return this.getOwnerTree().getSelectionModel().isSelected(this);
34828 * Expand this node.
34829 * @param {Boolean} deep (optional) True to expand all children as well
34830 * @param {Boolean} anim (optional) false to cancel the default animation
34831 * @param {Function} callback (optional) A callback to be called when
34832 * expanding this node completes (does not wait for deep expand to complete).
34833 * Called with 1 parameter, this node.
34835 expand : function(deep, anim, callback){
34836 if(!this.expanded){
34837 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34840 if(!this.childrenRendered){
34841 this.renderChildren();
34843 this.expanded = true;
34844 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34845 this.ui.animExpand(function(){
34846 this.fireEvent("expand", this);
34847 if(typeof callback == "function"){
34851 this.expandChildNodes(true);
34853 }.createDelegate(this));
34857 this.fireEvent("expand", this);
34858 if(typeof callback == "function"){
34863 if(typeof callback == "function"){
34868 this.expandChildNodes(true);
34872 isHiddenRoot : function(){
34873 return this.isRoot && !this.getOwnerTree().rootVisible;
34877 * Collapse this node.
34878 * @param {Boolean} deep (optional) True to collapse all children as well
34879 * @param {Boolean} anim (optional) false to cancel the default animation
34881 collapse : function(deep, anim){
34882 if(this.expanded && !this.isHiddenRoot()){
34883 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
34886 this.expanded = false;
34887 if((this.getOwnerTree().animate && anim !== false) || anim){
34888 this.ui.animCollapse(function(){
34889 this.fireEvent("collapse", this);
34891 this.collapseChildNodes(true);
34893 }.createDelegate(this));
34896 this.ui.collapse();
34897 this.fireEvent("collapse", this);
34901 var cs = this.childNodes;
34902 for(var i = 0, len = cs.length; i < len; i++) {
34903 cs[i].collapse(true, false);
34909 delayedExpand : function(delay){
34910 if(!this.expandProcId){
34911 this.expandProcId = this.expand.defer(delay, this);
34916 cancelExpand : function(){
34917 if(this.expandProcId){
34918 clearTimeout(this.expandProcId);
34920 this.expandProcId = false;
34924 * Toggles expanded/collapsed state of the node
34926 toggle : function(){
34935 * Ensures all parent nodes are expanded
34937 ensureVisible : function(callback){
34938 var tree = this.getOwnerTree();
34939 tree.expandPath(this.parentNode.getPath(), false, function(){
34940 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
34941 Roo.callback(callback);
34942 }.createDelegate(this));
34946 * Expand all child nodes
34947 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
34949 expandChildNodes : function(deep){
34950 var cs = this.childNodes;
34951 for(var i = 0, len = cs.length; i < len; i++) {
34952 cs[i].expand(deep);
34957 * Collapse all child nodes
34958 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
34960 collapseChildNodes : function(deep){
34961 var cs = this.childNodes;
34962 for(var i = 0, len = cs.length; i < len; i++) {
34963 cs[i].collapse(deep);
34968 * Disables this node
34970 disable : function(){
34971 this.disabled = true;
34973 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
34974 this.ui.onDisableChange(this, true);
34976 this.fireEvent("disabledchange", this, true);
34980 * Enables this node
34982 enable : function(){
34983 this.disabled = false;
34984 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
34985 this.ui.onDisableChange(this, false);
34987 this.fireEvent("disabledchange", this, false);
34991 renderChildren : function(suppressEvent){
34992 if(suppressEvent !== false){
34993 this.fireEvent("beforechildrenrendered", this);
34995 var cs = this.childNodes;
34996 for(var i = 0, len = cs.length; i < len; i++){
34997 cs[i].render(true);
34999 this.childrenRendered = true;
35003 sort : function(fn, scope){
35004 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35005 if(this.childrenRendered){
35006 var cs = this.childNodes;
35007 for(var i = 0, len = cs.length; i < len; i++){
35008 cs[i].render(true);
35014 render : function(bulkRender){
35015 this.ui.render(bulkRender);
35016 if(!this.rendered){
35017 this.rendered = true;
35019 this.expanded = false;
35020 this.expand(false, false);
35026 renderIndent : function(deep, refresh){
35028 this.ui.childIndent = null;
35030 this.ui.renderIndent();
35031 if(deep === true && this.childrenRendered){
35032 var cs = this.childNodes;
35033 for(var i = 0, len = cs.length; i < len; i++){
35034 cs[i].renderIndent(true, refresh);
35040 * Ext JS Library 1.1.1
35041 * Copyright(c) 2006-2007, Ext JS, LLC.
35043 * Originally Released Under LGPL - original licence link has changed is not relivant.
35046 * <script type="text/javascript">
35050 * @class Roo.tree.AsyncTreeNode
35051 * @extends Roo.tree.TreeNode
35052 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35054 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35056 Roo.tree.AsyncTreeNode = function(config){
35057 this.loaded = false;
35058 this.loading = false;
35059 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35061 * @event beforeload
35062 * Fires before this node is loaded, return false to cancel
35063 * @param {Node} this This node
35065 this.addEvents({'beforeload':true, 'load': true});
35068 * Fires when this node is loaded
35069 * @param {Node} this This node
35072 * The loader used by this node (defaults to using the tree's defined loader)
35077 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35078 expand : function(deep, anim, callback){
35079 if(this.loading){ // if an async load is already running, waiting til it's done
35081 var f = function(){
35082 if(!this.loading){ // done loading
35083 clearInterval(timer);
35084 this.expand(deep, anim, callback);
35086 }.createDelegate(this);
35087 timer = setInterval(f, 200);
35091 if(this.fireEvent("beforeload", this) === false){
35094 this.loading = true;
35095 this.ui.beforeLoad(this);
35096 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35098 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35102 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35106 * Returns true if this node is currently loading
35107 * @return {Boolean}
35109 isLoading : function(){
35110 return this.loading;
35113 loadComplete : function(deep, anim, callback){
35114 this.loading = false;
35115 this.loaded = true;
35116 this.ui.afterLoad(this);
35117 this.fireEvent("load", this);
35118 this.expand(deep, anim, callback);
35122 * Returns true if this node has been loaded
35123 * @return {Boolean}
35125 isLoaded : function(){
35126 return this.loaded;
35129 hasChildNodes : function(){
35130 if(!this.isLeaf() && !this.loaded){
35133 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35138 * Trigger a reload for this node
35139 * @param {Function} callback
35141 reload : function(callback){
35142 this.collapse(false, false);
35143 while(this.firstChild){
35144 this.removeChild(this.firstChild);
35146 this.childrenRendered = false;
35147 this.loaded = false;
35148 if(this.isHiddenRoot()){
35149 this.expanded = false;
35151 this.expand(false, false, callback);
35155 * Ext JS Library 1.1.1
35156 * Copyright(c) 2006-2007, Ext JS, LLC.
35158 * Originally Released Under LGPL - original licence link has changed is not relivant.
35161 * <script type="text/javascript">
35165 * @class Roo.tree.TreeNodeUI
35167 * @param {Object} node The node to render
35168 * The TreeNode UI implementation is separate from the
35169 * tree implementation. Unless you are customizing the tree UI,
35170 * you should never have to use this directly.
35172 Roo.tree.TreeNodeUI = function(node){
35174 this.rendered = false;
35175 this.animating = false;
35176 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35179 Roo.tree.TreeNodeUI.prototype = {
35180 removeChild : function(node){
35182 this.ctNode.removeChild(node.ui.getEl());
35186 beforeLoad : function(){
35187 this.addClass("x-tree-node-loading");
35190 afterLoad : function(){
35191 this.removeClass("x-tree-node-loading");
35194 onTextChange : function(node, text, oldText){
35196 this.textNode.innerHTML = text;
35200 onDisableChange : function(node, state){
35201 this.disabled = state;
35203 this.addClass("x-tree-node-disabled");
35205 this.removeClass("x-tree-node-disabled");
35209 onSelectedChange : function(state){
35212 this.addClass("x-tree-selected");
35215 this.removeClass("x-tree-selected");
35219 onMove : function(tree, node, oldParent, newParent, index, refNode){
35220 this.childIndent = null;
35222 var targetNode = newParent.ui.getContainer();
35223 if(!targetNode){//target not rendered
35224 this.holder = document.createElement("div");
35225 this.holder.appendChild(this.wrap);
35228 var insertBefore = refNode ? refNode.ui.getEl() : null;
35230 targetNode.insertBefore(this.wrap, insertBefore);
35232 targetNode.appendChild(this.wrap);
35234 this.node.renderIndent(true);
35238 addClass : function(cls){
35240 Roo.fly(this.elNode).addClass(cls);
35244 removeClass : function(cls){
35246 Roo.fly(this.elNode).removeClass(cls);
35250 remove : function(){
35252 this.holder = document.createElement("div");
35253 this.holder.appendChild(this.wrap);
35257 fireEvent : function(){
35258 return this.node.fireEvent.apply(this.node, arguments);
35261 initEvents : function(){
35262 this.node.on("move", this.onMove, this);
35263 var E = Roo.EventManager;
35264 var a = this.anchor;
35266 var el = Roo.fly(a, '_treeui');
35268 if(Roo.isOpera){ // opera render bug ignores the CSS
35269 el.setStyle("text-decoration", "none");
35272 el.on("click", this.onClick, this);
35273 el.on("dblclick", this.onDblClick, this);
35276 Roo.EventManager.on(this.checkbox,
35277 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35280 el.on("contextmenu", this.onContextMenu, this);
35282 var icon = Roo.fly(this.iconNode);
35283 icon.on("click", this.onClick, this);
35284 icon.on("dblclick", this.onDblClick, this);
35285 icon.on("contextmenu", this.onContextMenu, this);
35286 E.on(this.ecNode, "click", this.ecClick, this, true);
35288 if(this.node.disabled){
35289 this.addClass("x-tree-node-disabled");
35291 if(this.node.hidden){
35292 this.addClass("x-tree-node-disabled");
35294 var ot = this.node.getOwnerTree();
35295 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35296 if(dd && (!this.node.isRoot || ot.rootVisible)){
35297 Roo.dd.Registry.register(this.elNode, {
35299 handles: this.getDDHandles(),
35305 getDDHandles : function(){
35306 return [this.iconNode, this.textNode];
35311 this.wrap.style.display = "none";
35317 this.wrap.style.display = "";
35321 onContextMenu : function(e){
35322 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35323 e.preventDefault();
35325 this.fireEvent("contextmenu", this.node, e);
35329 onClick : function(e){
35334 if(this.fireEvent("beforeclick", this.node, e) !== false){
35335 if(!this.disabled && this.node.attributes.href){
35336 this.fireEvent("click", this.node, e);
35339 e.preventDefault();
35344 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35345 this.node.toggle();
35348 this.fireEvent("click", this.node, e);
35354 onDblClick : function(e){
35355 e.preventDefault();
35360 this.toggleCheck();
35362 if(!this.animating && this.node.hasChildNodes()){
35363 this.node.toggle();
35365 this.fireEvent("dblclick", this.node, e);
35368 onCheckChange : function(){
35369 var checked = this.checkbox.checked;
35370 this.node.attributes.checked = checked;
35371 this.fireEvent('checkchange', this.node, checked);
35374 ecClick : function(e){
35375 if(!this.animating && this.node.hasChildNodes()){
35376 this.node.toggle();
35380 startDrop : function(){
35381 this.dropping = true;
35384 // delayed drop so the click event doesn't get fired on a drop
35385 endDrop : function(){
35386 setTimeout(function(){
35387 this.dropping = false;
35388 }.createDelegate(this), 50);
35391 expand : function(){
35392 this.updateExpandIcon();
35393 this.ctNode.style.display = "";
35396 focus : function(){
35397 if(!this.node.preventHScroll){
35398 try{this.anchor.focus();
35400 }else if(!Roo.isIE){
35402 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35403 var l = noscroll.scrollLeft;
35404 this.anchor.focus();
35405 noscroll.scrollLeft = l;
35410 toggleCheck : function(value){
35411 var cb = this.checkbox;
35413 cb.checked = (value === undefined ? !cb.checked : value);
35419 this.anchor.blur();
35423 animExpand : function(callback){
35424 var ct = Roo.get(this.ctNode);
35426 if(!this.node.hasChildNodes()){
35427 this.updateExpandIcon();
35428 this.ctNode.style.display = "";
35429 Roo.callback(callback);
35432 this.animating = true;
35433 this.updateExpandIcon();
35436 callback : function(){
35437 this.animating = false;
35438 Roo.callback(callback);
35441 duration: this.node.ownerTree.duration || .25
35445 highlight : function(){
35446 var tree = this.node.getOwnerTree();
35447 Roo.fly(this.wrap).highlight(
35448 tree.hlColor || "C3DAF9",
35449 {endColor: tree.hlBaseColor}
35453 collapse : function(){
35454 this.updateExpandIcon();
35455 this.ctNode.style.display = "none";
35458 animCollapse : function(callback){
35459 var ct = Roo.get(this.ctNode);
35460 ct.enableDisplayMode('block');
35463 this.animating = true;
35464 this.updateExpandIcon();
35467 callback : function(){
35468 this.animating = false;
35469 Roo.callback(callback);
35472 duration: this.node.ownerTree.duration || .25
35476 getContainer : function(){
35477 return this.ctNode;
35480 getEl : function(){
35484 appendDDGhost : function(ghostNode){
35485 ghostNode.appendChild(this.elNode.cloneNode(true));
35488 getDDRepairXY : function(){
35489 return Roo.lib.Dom.getXY(this.iconNode);
35492 onRender : function(){
35496 render : function(bulkRender){
35497 var n = this.node, a = n.attributes;
35498 var targetNode = n.parentNode ?
35499 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35501 if(!this.rendered){
35502 this.rendered = true;
35504 this.renderElements(n, a, targetNode, bulkRender);
35507 if(this.textNode.setAttributeNS){
35508 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35510 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35513 this.textNode.setAttribute("ext:qtip", a.qtip);
35515 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35518 }else if(a.qtipCfg){
35519 a.qtipCfg.target = Roo.id(this.textNode);
35520 Roo.QuickTips.register(a.qtipCfg);
35523 if(!this.node.expanded){
35524 this.updateExpandIcon();
35527 if(bulkRender === true) {
35528 targetNode.appendChild(this.wrap);
35533 renderElements : function(n, a, targetNode, bulkRender)
35535 // add some indent caching, this helps performance when rendering a large tree
35536 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35537 var t = n.getOwnerTree();
35538 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35539 if (typeof(n.attributes.html) != 'undefined') {
35540 txt = n.attributes.html;
35542 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35543 var cb = typeof a.checked == 'boolean';
35544 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35545 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35546 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35547 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35548 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35549 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35550 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35551 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35552 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35553 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35556 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35557 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35558 n.nextSibling.ui.getEl(), buf.join(""));
35560 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35563 this.elNode = this.wrap.childNodes[0];
35564 this.ctNode = this.wrap.childNodes[1];
35565 var cs = this.elNode.childNodes;
35566 this.indentNode = cs[0];
35567 this.ecNode = cs[1];
35568 this.iconNode = cs[2];
35571 this.checkbox = cs[3];
35574 this.anchor = cs[index];
35575 this.textNode = cs[index].firstChild;
35578 getAnchor : function(){
35579 return this.anchor;
35582 getTextEl : function(){
35583 return this.textNode;
35586 getIconEl : function(){
35587 return this.iconNode;
35590 isChecked : function(){
35591 return this.checkbox ? this.checkbox.checked : false;
35594 updateExpandIcon : function(){
35596 var n = this.node, c1, c2;
35597 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35598 var hasChild = n.hasChildNodes();
35602 c1 = "x-tree-node-collapsed";
35603 c2 = "x-tree-node-expanded";
35606 c1 = "x-tree-node-expanded";
35607 c2 = "x-tree-node-collapsed";
35610 this.removeClass("x-tree-node-leaf");
35611 this.wasLeaf = false;
35613 if(this.c1 != c1 || this.c2 != c2){
35614 Roo.fly(this.elNode).replaceClass(c1, c2);
35615 this.c1 = c1; this.c2 = c2;
35618 // this changes non-leafs into leafs if they have no children.
35619 // it's not very rational behaviour..
35621 if(!this.wasLeaf && this.node.leaf){
35622 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35625 this.wasLeaf = true;
35628 var ecc = "x-tree-ec-icon "+cls;
35629 if(this.ecc != ecc){
35630 this.ecNode.className = ecc;
35636 getChildIndent : function(){
35637 if(!this.childIndent){
35641 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35643 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35645 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35650 this.childIndent = buf.join("");
35652 return this.childIndent;
35655 renderIndent : function(){
35658 var p = this.node.parentNode;
35660 indent = p.ui.getChildIndent();
35662 if(this.indentMarkup != indent){ // don't rerender if not required
35663 this.indentNode.innerHTML = indent;
35664 this.indentMarkup = indent;
35666 this.updateExpandIcon();
35671 Roo.tree.RootTreeNodeUI = function(){
35672 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35674 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35675 render : function(){
35676 if(!this.rendered){
35677 var targetNode = this.node.ownerTree.innerCt.dom;
35678 this.node.expanded = true;
35679 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35680 this.wrap = this.ctNode = targetNode.firstChild;
35683 collapse : function(){
35685 expand : function(){
35689 * Ext JS Library 1.1.1
35690 * Copyright(c) 2006-2007, Ext JS, LLC.
35692 * Originally Released Under LGPL - original licence link has changed is not relivant.
35695 * <script type="text/javascript">
35698 * @class Roo.tree.TreeLoader
35699 * @extends Roo.util.Observable
35700 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35701 * nodes from a specified URL. The response must be a javascript Array definition
35702 * who's elements are node definition objects. eg:
35707 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35708 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35715 * The old style respose with just an array is still supported, but not recommended.
35718 * A server request is sent, and child nodes are loaded only when a node is expanded.
35719 * The loading node's id is passed to the server under the parameter name "node" to
35720 * enable the server to produce the correct child nodes.
35722 * To pass extra parameters, an event handler may be attached to the "beforeload"
35723 * event, and the parameters specified in the TreeLoader's baseParams property:
35725 myTreeLoader.on("beforeload", function(treeLoader, node) {
35726 this.baseParams.category = node.attributes.category;
35729 * This would pass an HTTP parameter called "category" to the server containing
35730 * the value of the Node's "category" attribute.
35732 * Creates a new Treeloader.
35733 * @param {Object} config A config object containing config properties.
35735 Roo.tree.TreeLoader = function(config){
35736 this.baseParams = {};
35737 this.requestMethod = "POST";
35738 Roo.apply(this, config);
35743 * @event beforeload
35744 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35745 * @param {Object} This TreeLoader object.
35746 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35747 * @param {Object} callback The callback function specified in the {@link #load} call.
35752 * Fires when the node has been successfuly loaded.
35753 * @param {Object} This TreeLoader object.
35754 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35755 * @param {Object} response The response object containing the data from the server.
35759 * @event loadexception
35760 * Fires if the network request failed.
35761 * @param {Object} This TreeLoader object.
35762 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35763 * @param {Object} response The response object containing the data from the server.
35765 loadexception : true,
35768 * Fires before a node is created, enabling you to return custom Node types
35769 * @param {Object} This TreeLoader object.
35770 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35775 Roo.tree.TreeLoader.superclass.constructor.call(this);
35778 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35780 * @cfg {String} dataUrl The URL from which to request a Json string which
35781 * specifies an array of node definition object representing the child nodes
35785 * @cfg {String} requestMethod either GET or POST
35786 * defaults to POST (due to BC)
35790 * @cfg {Object} baseParams (optional) An object containing properties which
35791 * specify HTTP parameters to be passed to each request for child nodes.
35794 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35795 * created by this loader. If the attributes sent by the server have an attribute in this object,
35796 * they take priority.
35799 * @cfg {Object} uiProviders (optional) An object containing properties which
35801 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35802 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35803 * <i>uiProvider</i> attribute of a returned child node is a string rather
35804 * than a reference to a TreeNodeUI implementation, this that string value
35805 * is used as a property name in the uiProviders object. You can define the provider named
35806 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35811 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35812 * child nodes before loading.
35814 clearOnLoad : true,
35817 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35818 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35819 * Grid query { data : [ .....] }
35824 * @cfg {String} queryParam (optional)
35825 * Name of the query as it will be passed on the querystring (defaults to 'node')
35826 * eg. the request will be ?node=[id]
35833 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35834 * This is called automatically when a node is expanded, but may be used to reload
35835 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35836 * @param {Roo.tree.TreeNode} node
35837 * @param {Function} callback
35839 load : function(node, callback){
35840 if(this.clearOnLoad){
35841 while(node.firstChild){
35842 node.removeChild(node.firstChild);
35845 if(node.attributes.children){ // preloaded json children
35846 var cs = node.attributes.children;
35847 for(var i = 0, len = cs.length; i < len; i++){
35848 node.appendChild(this.createNode(cs[i]));
35850 if(typeof callback == "function"){
35853 }else if(this.dataUrl){
35854 this.requestData(node, callback);
35858 getParams: function(node){
35859 var buf = [], bp = this.baseParams;
35860 for(var key in bp){
35861 if(typeof bp[key] != "function"){
35862 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
35865 var n = this.queryParam === false ? 'node' : this.queryParam;
35866 buf.push(n + "=", encodeURIComponent(node.id));
35867 return buf.join("");
35870 requestData : function(node, callback){
35871 if(this.fireEvent("beforeload", this, node, callback) !== false){
35872 this.transId = Roo.Ajax.request({
35873 method:this.requestMethod,
35874 url: this.dataUrl||this.url,
35875 success: this.handleResponse,
35876 failure: this.handleFailure,
35878 argument: {callback: callback, node: node},
35879 params: this.getParams(node)
35882 // if the load is cancelled, make sure we notify
35883 // the node that we are done
35884 if(typeof callback == "function"){
35890 isLoading : function(){
35891 return this.transId ? true : false;
35894 abort : function(){
35895 if(this.isLoading()){
35896 Roo.Ajax.abort(this.transId);
35901 createNode : function(attr)
35903 // apply baseAttrs, nice idea Corey!
35904 if(this.baseAttrs){
35905 Roo.applyIf(attr, this.baseAttrs);
35907 if(this.applyLoader !== false){
35908 attr.loader = this;
35910 // uiProvider = depreciated..
35912 if(typeof(attr.uiProvider) == 'string'){
35913 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
35914 /** eval:var:attr */ eval(attr.uiProvider);
35916 if(typeof(this.uiProviders['default']) != 'undefined') {
35917 attr.uiProvider = this.uiProviders['default'];
35920 this.fireEvent('create', this, attr);
35922 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
35924 new Roo.tree.TreeNode(attr) :
35925 new Roo.tree.AsyncTreeNode(attr));
35928 processResponse : function(response, node, callback)
35930 var json = response.responseText;
35933 var o = Roo.decode(json);
35935 if (this.root === false && typeof(o.success) != undefined) {
35936 this.root = 'data'; // the default behaviour for list like data..
35939 if (this.root !== false && !o.success) {
35940 // it's a failure condition.
35941 var a = response.argument;
35942 this.fireEvent("loadexception", this, a.node, response);
35943 Roo.log("Load failed - should have a handler really");
35949 if (this.root !== false) {
35953 for(var i = 0, len = o.length; i < len; i++){
35954 var n = this.createNode(o[i]);
35956 node.appendChild(n);
35959 if(typeof callback == "function"){
35960 callback(this, node);
35963 this.handleFailure(response);
35967 handleResponse : function(response){
35968 this.transId = false;
35969 var a = response.argument;
35970 this.processResponse(response, a.node, a.callback);
35971 this.fireEvent("load", this, a.node, response);
35974 handleFailure : function(response)
35976 // should handle failure better..
35977 this.transId = false;
35978 var a = response.argument;
35979 this.fireEvent("loadexception", this, a.node, response);
35980 if(typeof a.callback == "function"){
35981 a.callback(this, a.node);
35986 * Ext JS Library 1.1.1
35987 * Copyright(c) 2006-2007, Ext JS, LLC.
35989 * Originally Released Under LGPL - original licence link has changed is not relivant.
35992 * <script type="text/javascript">
35996 * @class Roo.tree.TreeFilter
35997 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
35998 * @param {TreePanel} tree
35999 * @param {Object} config (optional)
36001 Roo.tree.TreeFilter = function(tree, config){
36003 this.filtered = {};
36004 Roo.apply(this, config);
36007 Roo.tree.TreeFilter.prototype = {
36014 * Filter the data by a specific attribute.
36015 * @param {String/RegExp} value Either string that the attribute value
36016 * should start with or a RegExp to test against the attribute
36017 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36018 * @param {TreeNode} startNode (optional) The node to start the filter at.
36020 filter : function(value, attr, startNode){
36021 attr = attr || "text";
36023 if(typeof value == "string"){
36024 var vlen = value.length;
36025 // auto clear empty filter
36026 if(vlen == 0 && this.clearBlank){
36030 value = value.toLowerCase();
36032 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36034 }else if(value.exec){ // regex?
36036 return value.test(n.attributes[attr]);
36039 throw 'Illegal filter type, must be string or regex';
36041 this.filterBy(f, null, startNode);
36045 * Filter by a function. The passed function will be called with each
36046 * node in the tree (or from the startNode). If the function returns true, the node is kept
36047 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36048 * @param {Function} fn The filter function
36049 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36051 filterBy : function(fn, scope, startNode){
36052 startNode = startNode || this.tree.root;
36053 if(this.autoClear){
36056 var af = this.filtered, rv = this.reverse;
36057 var f = function(n){
36058 if(n == startNode){
36064 var m = fn.call(scope || n, n);
36072 startNode.cascade(f);
36075 if(typeof id != "function"){
36077 if(n && n.parentNode){
36078 n.parentNode.removeChild(n);
36086 * Clears the current filter. Note: with the "remove" option
36087 * set a filter cannot be cleared.
36089 clear : function(){
36091 var af = this.filtered;
36093 if(typeof id != "function"){
36100 this.filtered = {};
36105 * Ext JS Library 1.1.1
36106 * Copyright(c) 2006-2007, Ext JS, LLC.
36108 * Originally Released Under LGPL - original licence link has changed is not relivant.
36111 * <script type="text/javascript">
36116 * @class Roo.tree.TreeSorter
36117 * Provides sorting of nodes in a TreePanel
36119 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36120 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36121 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36122 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36123 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36124 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36126 * @param {TreePanel} tree
36127 * @param {Object} config
36129 Roo.tree.TreeSorter = function(tree, config){
36130 Roo.apply(this, config);
36131 tree.on("beforechildrenrendered", this.doSort, this);
36132 tree.on("append", this.updateSort, this);
36133 tree.on("insert", this.updateSort, this);
36135 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36136 var p = this.property || "text";
36137 var sortType = this.sortType;
36138 var fs = this.folderSort;
36139 var cs = this.caseSensitive === true;
36140 var leafAttr = this.leafAttr || 'leaf';
36142 this.sortFn = function(n1, n2){
36144 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36147 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36151 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36152 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36154 return dsc ? +1 : -1;
36156 return dsc ? -1 : +1;
36163 Roo.tree.TreeSorter.prototype = {
36164 doSort : function(node){
36165 node.sort(this.sortFn);
36168 compareNodes : function(n1, n2){
36169 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36172 updateSort : function(tree, node){
36173 if(node.childrenRendered){
36174 this.doSort.defer(1, this, [node]);
36179 * Ext JS Library 1.1.1
36180 * Copyright(c) 2006-2007, Ext JS, LLC.
36182 * Originally Released Under LGPL - original licence link has changed is not relivant.
36185 * <script type="text/javascript">
36188 if(Roo.dd.DropZone){
36190 Roo.tree.TreeDropZone = function(tree, config){
36191 this.allowParentInsert = false;
36192 this.allowContainerDrop = false;
36193 this.appendOnly = false;
36194 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36196 this.lastInsertClass = "x-tree-no-status";
36197 this.dragOverData = {};
36200 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36201 ddGroup : "TreeDD",
36204 expandDelay : 1000,
36206 expandNode : function(node){
36207 if(node.hasChildNodes() && !node.isExpanded()){
36208 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36212 queueExpand : function(node){
36213 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36216 cancelExpand : function(){
36217 if(this.expandProcId){
36218 clearTimeout(this.expandProcId);
36219 this.expandProcId = false;
36223 isValidDropPoint : function(n, pt, dd, e, data){
36224 if(!n || !data){ return false; }
36225 var targetNode = n.node;
36226 var dropNode = data.node;
36227 // default drop rules
36228 if(!(targetNode && targetNode.isTarget && pt)){
36231 if(pt == "append" && targetNode.allowChildren === false){
36234 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36237 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36240 // reuse the object
36241 var overEvent = this.dragOverData;
36242 overEvent.tree = this.tree;
36243 overEvent.target = targetNode;
36244 overEvent.data = data;
36245 overEvent.point = pt;
36246 overEvent.source = dd;
36247 overEvent.rawEvent = e;
36248 overEvent.dropNode = dropNode;
36249 overEvent.cancel = false;
36250 var result = this.tree.fireEvent("nodedragover", overEvent);
36251 return overEvent.cancel === false && result !== false;
36254 getDropPoint : function(e, n, dd)
36258 return tn.allowChildren !== false ? "append" : false; // always append for root
36260 var dragEl = n.ddel;
36261 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36262 var y = Roo.lib.Event.getPageY(e);
36263 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36265 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36266 var noAppend = tn.allowChildren === false;
36267 if(this.appendOnly || tn.parentNode.allowChildren === false){
36268 return noAppend ? false : "append";
36270 var noBelow = false;
36271 if(!this.allowParentInsert){
36272 noBelow = tn.hasChildNodes() && tn.isExpanded();
36274 var q = (b - t) / (noAppend ? 2 : 3);
36275 if(y >= t && y < (t + q)){
36277 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36284 onNodeEnter : function(n, dd, e, data)
36286 this.cancelExpand();
36289 onNodeOver : function(n, dd, e, data)
36292 var pt = this.getDropPoint(e, n, dd);
36295 // auto node expand check
36296 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36297 this.queueExpand(node);
36298 }else if(pt != "append"){
36299 this.cancelExpand();
36302 // set the insert point style on the target node
36303 var returnCls = this.dropNotAllowed;
36304 if(this.isValidDropPoint(n, pt, dd, e, data)){
36309 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36310 cls = "x-tree-drag-insert-above";
36311 }else if(pt == "below"){
36312 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36313 cls = "x-tree-drag-insert-below";
36315 returnCls = "x-tree-drop-ok-append";
36316 cls = "x-tree-drag-append";
36318 if(this.lastInsertClass != cls){
36319 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36320 this.lastInsertClass = cls;
36327 onNodeOut : function(n, dd, e, data){
36329 this.cancelExpand();
36330 this.removeDropIndicators(n);
36333 onNodeDrop : function(n, dd, e, data){
36334 var point = this.getDropPoint(e, n, dd);
36335 var targetNode = n.node;
36336 targetNode.ui.startDrop();
36337 if(!this.isValidDropPoint(n, point, dd, e, data)){
36338 targetNode.ui.endDrop();
36341 // first try to find the drop node
36342 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36345 target: targetNode,
36350 dropNode: dropNode,
36353 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36354 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36355 targetNode.ui.endDrop();
36358 // allow target changing
36359 targetNode = dropEvent.target;
36360 if(point == "append" && !targetNode.isExpanded()){
36361 targetNode.expand(false, null, function(){
36362 this.completeDrop(dropEvent);
36363 }.createDelegate(this));
36365 this.completeDrop(dropEvent);
36370 completeDrop : function(de){
36371 var ns = de.dropNode, p = de.point, t = de.target;
36372 if(!(ns instanceof Array)){
36376 for(var i = 0, len = ns.length; i < len; i++){
36379 t.parentNode.insertBefore(n, t);
36380 }else if(p == "below"){
36381 t.parentNode.insertBefore(n, t.nextSibling);
36387 if(this.tree.hlDrop){
36391 this.tree.fireEvent("nodedrop", de);
36394 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36395 if(this.tree.hlDrop){
36396 dropNode.ui.focus();
36397 dropNode.ui.highlight();
36399 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36402 getTree : function(){
36406 removeDropIndicators : function(n){
36409 Roo.fly(el).removeClass([
36410 "x-tree-drag-insert-above",
36411 "x-tree-drag-insert-below",
36412 "x-tree-drag-append"]);
36413 this.lastInsertClass = "_noclass";
36417 beforeDragDrop : function(target, e, id){
36418 this.cancelExpand();
36422 afterRepair : function(data){
36423 if(data && Roo.enableFx){
36424 data.node.ui.highlight();
36434 * Ext JS Library 1.1.1
36435 * Copyright(c) 2006-2007, Ext JS, LLC.
36437 * Originally Released Under LGPL - original licence link has changed is not relivant.
36440 * <script type="text/javascript">
36444 if(Roo.dd.DragZone){
36445 Roo.tree.TreeDragZone = function(tree, config){
36446 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36450 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36451 ddGroup : "TreeDD",
36453 onBeforeDrag : function(data, e){
36455 return n && n.draggable && !n.disabled;
36459 onInitDrag : function(e){
36460 var data = this.dragData;
36461 this.tree.getSelectionModel().select(data.node);
36462 this.proxy.update("");
36463 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36464 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36467 getRepairXY : function(e, data){
36468 return data.node.ui.getDDRepairXY();
36471 onEndDrag : function(data, e){
36472 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36477 onValidDrop : function(dd, e, id){
36478 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36482 beforeInvalidDrop : function(e, id){
36483 // this scrolls the original position back into view
36484 var sm = this.tree.getSelectionModel();
36485 sm.clearSelections();
36486 sm.select(this.dragData.node);
36491 * Ext JS Library 1.1.1
36492 * Copyright(c) 2006-2007, Ext JS, LLC.
36494 * Originally Released Under LGPL - original licence link has changed is not relivant.
36497 * <script type="text/javascript">
36500 * @class Roo.tree.TreeEditor
36501 * @extends Roo.Editor
36502 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36503 * as the editor field.
36505 * @param {Object} config (used to be the tree panel.)
36506 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36508 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36509 * @cfg {Roo.form.TextField|Object} field The field configuration
36513 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36516 if (oldconfig) { // old style..
36517 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36520 tree = config.tree;
36521 config.field = config.field || {};
36522 config.field.xtype = 'TextField';
36523 field = Roo.factory(config.field, Roo.form);
36525 config = config || {};
36530 * @event beforenodeedit
36531 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36532 * false from the handler of this event.
36533 * @param {Editor} this
36534 * @param {Roo.tree.Node} node
36536 "beforenodeedit" : true
36540 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36544 tree.on('beforeclick', this.beforeNodeClick, this);
36545 tree.getTreeEl().on('mousedown', this.hide, this);
36546 this.on('complete', this.updateNode, this);
36547 this.on('beforestartedit', this.fitToTree, this);
36548 this.on('startedit', this.bindScroll, this, {delay:10});
36549 this.on('specialkey', this.onSpecialKey, this);
36552 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36554 * @cfg {String} alignment
36555 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36561 * @cfg {Boolean} hideEl
36562 * True to hide the bound element while the editor is displayed (defaults to false)
36566 * @cfg {String} cls
36567 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36569 cls: "x-small-editor x-tree-editor",
36571 * @cfg {Boolean} shim
36572 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36578 * @cfg {Number} maxWidth
36579 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36580 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36581 * scroll and client offsets into account prior to each edit.
36588 fitToTree : function(ed, el){
36589 var td = this.tree.getTreeEl().dom, nd = el.dom;
36590 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36591 td.scrollLeft = nd.offsetLeft;
36595 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36596 this.setSize(w, '');
36598 return this.fireEvent('beforenodeedit', this, this.editNode);
36603 triggerEdit : function(node){
36604 this.completeEdit();
36605 this.editNode = node;
36606 this.startEdit(node.ui.textNode, node.text);
36610 bindScroll : function(){
36611 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36615 beforeNodeClick : function(node, e){
36616 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36617 this.lastClick = new Date();
36618 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36620 this.triggerEdit(node);
36627 updateNode : function(ed, value){
36628 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36629 this.editNode.setText(value);
36633 onHide : function(){
36634 Roo.tree.TreeEditor.superclass.onHide.call(this);
36636 this.editNode.ui.focus();
36641 onSpecialKey : function(field, e){
36642 var k = e.getKey();
36646 }else if(k == e.ENTER && !e.hasModifier()){
36648 this.completeEdit();
36651 });//<Script type="text/javascript">
36654 * Ext JS Library 1.1.1
36655 * Copyright(c) 2006-2007, Ext JS, LLC.
36657 * Originally Released Under LGPL - original licence link has changed is not relivant.
36660 * <script type="text/javascript">
36664 * Not documented??? - probably should be...
36667 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36668 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36670 renderElements : function(n, a, targetNode, bulkRender){
36671 //consel.log("renderElements?");
36672 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36674 var t = n.getOwnerTree();
36675 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36677 var cols = t.columns;
36678 var bw = t.borderWidth;
36680 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36681 var cb = typeof a.checked == "boolean";
36682 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36683 var colcls = 'x-t-' + tid + '-c0';
36685 '<li class="x-tree-node">',
36688 '<div class="x-tree-node-el ', a.cls,'">',
36690 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36693 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36694 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36695 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36696 (a.icon ? ' x-tree-node-inline-icon' : ''),
36697 (a.iconCls ? ' '+a.iconCls : ''),
36698 '" unselectable="on" />',
36699 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36700 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36702 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36703 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36704 '<span unselectable="on" qtip="' + tx + '">',
36708 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36709 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36711 for(var i = 1, len = cols.length; i < len; i++){
36713 colcls = 'x-t-' + tid + '-c' +i;
36714 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36715 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36716 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36722 '<div class="x-clear"></div></div>',
36723 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36726 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36727 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36728 n.nextSibling.ui.getEl(), buf.join(""));
36730 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36732 var el = this.wrap.firstChild;
36734 this.elNode = el.firstChild;
36735 this.ranchor = el.childNodes[1];
36736 this.ctNode = this.wrap.childNodes[1];
36737 var cs = el.firstChild.childNodes;
36738 this.indentNode = cs[0];
36739 this.ecNode = cs[1];
36740 this.iconNode = cs[2];
36743 this.checkbox = cs[3];
36746 this.anchor = cs[index];
36748 this.textNode = cs[index].firstChild;
36750 //el.on("click", this.onClick, this);
36751 //el.on("dblclick", this.onDblClick, this);
36754 // console.log(this);
36756 initEvents : function(){
36757 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36760 var a = this.ranchor;
36762 var el = Roo.get(a);
36764 if(Roo.isOpera){ // opera render bug ignores the CSS
36765 el.setStyle("text-decoration", "none");
36768 el.on("click", this.onClick, this);
36769 el.on("dblclick", this.onDblClick, this);
36770 el.on("contextmenu", this.onContextMenu, this);
36774 /*onSelectedChange : function(state){
36777 this.addClass("x-tree-selected");
36780 this.removeClass("x-tree-selected");
36783 addClass : function(cls){
36785 Roo.fly(this.elRow).addClass(cls);
36791 removeClass : function(cls){
36793 Roo.fly(this.elRow).removeClass(cls);
36799 });//<Script type="text/javascript">
36803 * Ext JS Library 1.1.1
36804 * Copyright(c) 2006-2007, Ext JS, LLC.
36806 * Originally Released Under LGPL - original licence link has changed is not relivant.
36809 * <script type="text/javascript">
36814 * @class Roo.tree.ColumnTree
36815 * @extends Roo.data.TreePanel
36816 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36817 * @cfg {int} borderWidth compined right/left border allowance
36819 * @param {String/HTMLElement/Element} el The container element
36820 * @param {Object} config
36822 Roo.tree.ColumnTree = function(el, config)
36824 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36828 * Fire this event on a container when it resizes
36829 * @param {int} w Width
36830 * @param {int} h Height
36834 this.on('resize', this.onResize, this);
36837 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36841 borderWidth: Roo.isBorderBox ? 0 : 2,
36844 render : function(){
36845 // add the header.....
36847 Roo.tree.ColumnTree.superclass.render.apply(this);
36849 this.el.addClass('x-column-tree');
36851 this.headers = this.el.createChild(
36852 {cls:'x-tree-headers'},this.innerCt.dom);
36854 var cols = this.columns, c;
36855 var totalWidth = 0;
36857 var len = cols.length;
36858 for(var i = 0; i < len; i++){
36860 totalWidth += c.width;
36861 this.headEls.push(this.headers.createChild({
36862 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
36864 cls:'x-tree-hd-text',
36867 style:'width:'+(c.width-this.borderWidth)+'px;'
36870 this.headers.createChild({cls:'x-clear'});
36871 // prevent floats from wrapping when clipped
36872 this.headers.setWidth(totalWidth);
36873 //this.innerCt.setWidth(totalWidth);
36874 this.innerCt.setStyle({ overflow: 'auto' });
36875 this.onResize(this.width, this.height);
36879 onResize : function(w,h)
36884 this.innerCt.setWidth(this.width);
36885 this.innerCt.setHeight(this.height-20);
36888 var cols = this.columns, c;
36889 var totalWidth = 0;
36891 var len = cols.length;
36892 for(var i = 0; i < len; i++){
36894 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
36895 // it's the expander..
36896 expEl = this.headEls[i];
36899 totalWidth += c.width;
36903 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
36905 this.headers.setWidth(w-20);
36914 * Ext JS Library 1.1.1
36915 * Copyright(c) 2006-2007, Ext JS, LLC.
36917 * Originally Released Under LGPL - original licence link has changed is not relivant.
36920 * <script type="text/javascript">
36924 * @class Roo.menu.Menu
36925 * @extends Roo.util.Observable
36926 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
36927 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
36929 * Creates a new Menu
36930 * @param {Object} config Configuration options
36932 Roo.menu.Menu = function(config){
36933 Roo.apply(this, config);
36934 this.id = this.id || Roo.id();
36937 * @event beforeshow
36938 * Fires before this menu is displayed
36939 * @param {Roo.menu.Menu} this
36943 * @event beforehide
36944 * Fires before this menu is hidden
36945 * @param {Roo.menu.Menu} this
36950 * Fires after this menu is displayed
36951 * @param {Roo.menu.Menu} this
36956 * Fires after this menu is hidden
36957 * @param {Roo.menu.Menu} this
36962 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
36963 * @param {Roo.menu.Menu} this
36964 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36965 * @param {Roo.EventObject} e
36970 * Fires when the mouse is hovering over this menu
36971 * @param {Roo.menu.Menu} this
36972 * @param {Roo.EventObject} e
36973 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36978 * Fires when the mouse exits this menu
36979 * @param {Roo.menu.Menu} this
36980 * @param {Roo.EventObject} e
36981 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36986 * Fires when a menu item contained in this menu is clicked
36987 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
36988 * @param {Roo.EventObject} e
36992 if (this.registerMenu) {
36993 Roo.menu.MenuMgr.register(this);
36996 var mis = this.items;
36997 this.items = new Roo.util.MixedCollection();
36999 this.add.apply(this, mis);
37003 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37005 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37009 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37010 * for bottom-right shadow (defaults to "sides")
37014 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37015 * this menu (defaults to "tl-tr?")
37017 subMenuAlign : "tl-tr?",
37019 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37020 * relative to its element of origin (defaults to "tl-bl?")
37022 defaultAlign : "tl-bl?",
37024 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37026 allowOtherMenus : false,
37028 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37030 registerMenu : true,
37035 render : function(){
37039 var el = this.el = new Roo.Layer({
37041 shadow:this.shadow,
37043 parentEl: this.parentEl || document.body,
37047 this.keyNav = new Roo.menu.MenuNav(this);
37050 el.addClass("x-menu-plain");
37053 el.addClass(this.cls);
37055 // generic focus element
37056 this.focusEl = el.createChild({
37057 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37059 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37060 //disabling touch- as it's causing issues ..
37061 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37062 ul.on('click' , this.onClick, this);
37065 ul.on("mouseover", this.onMouseOver, this);
37066 ul.on("mouseout", this.onMouseOut, this);
37067 this.items.each(function(item){
37072 var li = document.createElement("li");
37073 li.className = "x-menu-list-item";
37074 ul.dom.appendChild(li);
37075 item.render(li, this);
37082 autoWidth : function(){
37083 var el = this.el, ul = this.ul;
37087 var w = this.width;
37090 }else if(Roo.isIE){
37091 el.setWidth(this.minWidth);
37092 var t = el.dom.offsetWidth; // force recalc
37093 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37098 delayAutoWidth : function(){
37101 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37103 this.awTask.delay(20);
37108 findTargetItem : function(e){
37109 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37110 if(t && t.menuItemId){
37111 return this.items.get(t.menuItemId);
37116 onClick : function(e){
37117 Roo.log("menu.onClick");
37118 var t = this.findTargetItem(e);
37123 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37124 if(t == this.activeItem && t.shouldDeactivate(e)){
37125 this.activeItem.deactivate();
37126 delete this.activeItem;
37130 this.setActiveItem(t, true);
37138 this.fireEvent("click", this, t, e);
37142 setActiveItem : function(item, autoExpand){
37143 if(item != this.activeItem){
37144 if(this.activeItem){
37145 this.activeItem.deactivate();
37147 this.activeItem = item;
37148 item.activate(autoExpand);
37149 }else if(autoExpand){
37155 tryActivate : function(start, step){
37156 var items = this.items;
37157 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37158 var item = items.get(i);
37159 if(!item.disabled && item.canActivate){
37160 this.setActiveItem(item, false);
37168 onMouseOver : function(e){
37170 if(t = this.findTargetItem(e)){
37171 if(t.canActivate && !t.disabled){
37172 this.setActiveItem(t, true);
37175 this.fireEvent("mouseover", this, e, t);
37179 onMouseOut : function(e){
37181 if(t = this.findTargetItem(e)){
37182 if(t == this.activeItem && t.shouldDeactivate(e)){
37183 this.activeItem.deactivate();
37184 delete this.activeItem;
37187 this.fireEvent("mouseout", this, e, t);
37191 * Read-only. Returns true if the menu is currently displayed, else false.
37194 isVisible : function(){
37195 return this.el && !this.hidden;
37199 * Displays this menu relative to another element
37200 * @param {String/HTMLElement/Roo.Element} element The element to align to
37201 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37202 * the element (defaults to this.defaultAlign)
37203 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37205 show : function(el, pos, parentMenu){
37206 this.parentMenu = parentMenu;
37210 this.fireEvent("beforeshow", this);
37211 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37215 * Displays this menu at a specific xy position
37216 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37217 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37219 showAt : function(xy, parentMenu, /* private: */_e){
37220 this.parentMenu = parentMenu;
37225 this.fireEvent("beforeshow", this);
37226 xy = this.el.adjustForConstraints(xy);
37230 this.hidden = false;
37232 this.fireEvent("show", this);
37235 focus : function(){
37237 this.doFocus.defer(50, this);
37241 doFocus : function(){
37243 this.focusEl.focus();
37248 * Hides this menu and optionally all parent menus
37249 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37251 hide : function(deep){
37252 if(this.el && this.isVisible()){
37253 this.fireEvent("beforehide", this);
37254 if(this.activeItem){
37255 this.activeItem.deactivate();
37256 this.activeItem = null;
37259 this.hidden = true;
37260 this.fireEvent("hide", this);
37262 if(deep === true && this.parentMenu){
37263 this.parentMenu.hide(true);
37268 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37269 * Any of the following are valid:
37271 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37272 * <li>An HTMLElement object which will be converted to a menu item</li>
37273 * <li>A menu item config object that will be created as a new menu item</li>
37274 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37275 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37280 var menu = new Roo.menu.Menu();
37282 // Create a menu item to add by reference
37283 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37285 // Add a bunch of items at once using different methods.
37286 // Only the last item added will be returned.
37287 var item = menu.add(
37288 menuItem, // add existing item by ref
37289 'Dynamic Item', // new TextItem
37290 '-', // new separator
37291 { text: 'Config Item' } // new item by config
37294 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37295 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37298 var a = arguments, l = a.length, item;
37299 for(var i = 0; i < l; i++){
37301 if ((typeof(el) == "object") && el.xtype && el.xns) {
37302 el = Roo.factory(el, Roo.menu);
37305 if(el.render){ // some kind of Item
37306 item = this.addItem(el);
37307 }else if(typeof el == "string"){ // string
37308 if(el == "separator" || el == "-"){
37309 item = this.addSeparator();
37311 item = this.addText(el);
37313 }else if(el.tagName || el.el){ // element
37314 item = this.addElement(el);
37315 }else if(typeof el == "object"){ // must be menu item config?
37316 item = this.addMenuItem(el);
37323 * Returns this menu's underlying {@link Roo.Element} object
37324 * @return {Roo.Element} The element
37326 getEl : function(){
37334 * Adds a separator bar to the menu
37335 * @return {Roo.menu.Item} The menu item that was added
37337 addSeparator : function(){
37338 return this.addItem(new Roo.menu.Separator());
37342 * Adds an {@link Roo.Element} object to the menu
37343 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37344 * @return {Roo.menu.Item} The menu item that was added
37346 addElement : function(el){
37347 return this.addItem(new Roo.menu.BaseItem(el));
37351 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37352 * @param {Roo.menu.Item} item The menu item to add
37353 * @return {Roo.menu.Item} The menu item that was added
37355 addItem : function(item){
37356 this.items.add(item);
37358 var li = document.createElement("li");
37359 li.className = "x-menu-list-item";
37360 this.ul.dom.appendChild(li);
37361 item.render(li, this);
37362 this.delayAutoWidth();
37368 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37369 * @param {Object} config A MenuItem config object
37370 * @return {Roo.menu.Item} The menu item that was added
37372 addMenuItem : function(config){
37373 if(!(config instanceof Roo.menu.Item)){
37374 if(typeof config.checked == "boolean"){ // must be check menu item config?
37375 config = new Roo.menu.CheckItem(config);
37377 config = new Roo.menu.Item(config);
37380 return this.addItem(config);
37384 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37385 * @param {String} text The text to display in the menu item
37386 * @return {Roo.menu.Item} The menu item that was added
37388 addText : function(text){
37389 return this.addItem(new Roo.menu.TextItem({ text : text }));
37393 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37394 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37395 * @param {Roo.menu.Item} item The menu item to add
37396 * @return {Roo.menu.Item} The menu item that was added
37398 insert : function(index, item){
37399 this.items.insert(index, item);
37401 var li = document.createElement("li");
37402 li.className = "x-menu-list-item";
37403 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37404 item.render(li, this);
37405 this.delayAutoWidth();
37411 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37412 * @param {Roo.menu.Item} item The menu item to remove
37414 remove : function(item){
37415 this.items.removeKey(item.id);
37420 * Removes and destroys all items in the menu
37422 removeAll : function(){
37424 while(f = this.items.first()){
37430 // MenuNav is a private utility class used internally by the Menu
37431 Roo.menu.MenuNav = function(menu){
37432 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37433 this.scope = this.menu = menu;
37436 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37437 doRelay : function(e, h){
37438 var k = e.getKey();
37439 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37440 this.menu.tryActivate(0, 1);
37443 return h.call(this.scope || this, e, this.menu);
37446 up : function(e, m){
37447 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37448 m.tryActivate(m.items.length-1, -1);
37452 down : function(e, m){
37453 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37454 m.tryActivate(0, 1);
37458 right : function(e, m){
37460 m.activeItem.expandMenu(true);
37464 left : function(e, m){
37466 if(m.parentMenu && m.parentMenu.activeItem){
37467 m.parentMenu.activeItem.activate();
37471 enter : function(e, m){
37473 e.stopPropagation();
37474 m.activeItem.onClick(e);
37475 m.fireEvent("click", this, m.activeItem);
37481 * Ext JS Library 1.1.1
37482 * Copyright(c) 2006-2007, Ext JS, LLC.
37484 * Originally Released Under LGPL - original licence link has changed is not relivant.
37487 * <script type="text/javascript">
37491 * @class Roo.menu.MenuMgr
37492 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37495 Roo.menu.MenuMgr = function(){
37496 var menus, active, groups = {}, attached = false, lastShow = new Date();
37498 // private - called when first menu is created
37501 active = new Roo.util.MixedCollection();
37502 Roo.get(document).addKeyListener(27, function(){
37503 if(active.length > 0){
37510 function hideAll(){
37511 if(active && active.length > 0){
37512 var c = active.clone();
37513 c.each(function(m){
37520 function onHide(m){
37522 if(active.length < 1){
37523 Roo.get(document).un("mousedown", onMouseDown);
37529 function onShow(m){
37530 var last = active.last();
37531 lastShow = new Date();
37534 Roo.get(document).on("mousedown", onMouseDown);
37538 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37539 m.parentMenu.activeChild = m;
37540 }else if(last && last.isVisible()){
37541 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37546 function onBeforeHide(m){
37548 m.activeChild.hide();
37550 if(m.autoHideTimer){
37551 clearTimeout(m.autoHideTimer);
37552 delete m.autoHideTimer;
37557 function onBeforeShow(m){
37558 var pm = m.parentMenu;
37559 if(!pm && !m.allowOtherMenus){
37561 }else if(pm && pm.activeChild && active != m){
37562 pm.activeChild.hide();
37567 function onMouseDown(e){
37568 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37574 function onBeforeCheck(mi, state){
37576 var g = groups[mi.group];
37577 for(var i = 0, l = g.length; i < l; i++){
37579 g[i].setChecked(false);
37588 * Hides all menus that are currently visible
37590 hideAll : function(){
37595 register : function(menu){
37599 menus[menu.id] = menu;
37600 menu.on("beforehide", onBeforeHide);
37601 menu.on("hide", onHide);
37602 menu.on("beforeshow", onBeforeShow);
37603 menu.on("show", onShow);
37604 var g = menu.group;
37605 if(g && menu.events["checkchange"]){
37609 groups[g].push(menu);
37610 menu.on("checkchange", onCheck);
37615 * Returns a {@link Roo.menu.Menu} object
37616 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37617 * be used to generate and return a new Menu instance.
37619 get : function(menu){
37620 if(typeof menu == "string"){ // menu id
37621 return menus[menu];
37622 }else if(menu.events){ // menu instance
37624 }else if(typeof menu.length == 'number'){ // array of menu items?
37625 return new Roo.menu.Menu({items:menu});
37626 }else{ // otherwise, must be a config
37627 return new Roo.menu.Menu(menu);
37632 unregister : function(menu){
37633 delete menus[menu.id];
37634 menu.un("beforehide", onBeforeHide);
37635 menu.un("hide", onHide);
37636 menu.un("beforeshow", onBeforeShow);
37637 menu.un("show", onShow);
37638 var g = menu.group;
37639 if(g && menu.events["checkchange"]){
37640 groups[g].remove(menu);
37641 menu.un("checkchange", onCheck);
37646 registerCheckable : function(menuItem){
37647 var g = menuItem.group;
37652 groups[g].push(menuItem);
37653 menuItem.on("beforecheckchange", onBeforeCheck);
37658 unregisterCheckable : function(menuItem){
37659 var g = menuItem.group;
37661 groups[g].remove(menuItem);
37662 menuItem.un("beforecheckchange", onBeforeCheck);
37668 * Ext JS Library 1.1.1
37669 * Copyright(c) 2006-2007, Ext JS, LLC.
37671 * Originally Released Under LGPL - original licence link has changed is not relivant.
37674 * <script type="text/javascript">
37679 * @class Roo.menu.BaseItem
37680 * @extends Roo.Component
37681 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37682 * management and base configuration options shared by all menu components.
37684 * Creates a new BaseItem
37685 * @param {Object} config Configuration options
37687 Roo.menu.BaseItem = function(config){
37688 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37693 * Fires when this item is clicked
37694 * @param {Roo.menu.BaseItem} this
37695 * @param {Roo.EventObject} e
37700 * Fires when this item is activated
37701 * @param {Roo.menu.BaseItem} this
37705 * @event deactivate
37706 * Fires when this item is deactivated
37707 * @param {Roo.menu.BaseItem} this
37713 this.on("click", this.handler, this.scope, true);
37717 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37719 * @cfg {Function} handler
37720 * A function that will handle the click event of this menu item (defaults to undefined)
37723 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37725 canActivate : false,
37728 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37733 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37735 activeClass : "x-menu-item-active",
37737 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37739 hideOnClick : true,
37741 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37746 ctype: "Roo.menu.BaseItem",
37749 actionMode : "container",
37752 render : function(container, parentMenu){
37753 this.parentMenu = parentMenu;
37754 Roo.menu.BaseItem.superclass.render.call(this, container);
37755 this.container.menuItemId = this.id;
37759 onRender : function(container, position){
37760 this.el = Roo.get(this.el);
37761 container.dom.appendChild(this.el.dom);
37765 onClick : function(e){
37766 if(!this.disabled && this.fireEvent("click", this, e) !== false
37767 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37768 this.handleClick(e);
37775 activate : function(){
37779 var li = this.container;
37780 li.addClass(this.activeClass);
37781 this.region = li.getRegion().adjust(2, 2, -2, -2);
37782 this.fireEvent("activate", this);
37787 deactivate : function(){
37788 this.container.removeClass(this.activeClass);
37789 this.fireEvent("deactivate", this);
37793 shouldDeactivate : function(e){
37794 return !this.region || !this.region.contains(e.getPoint());
37798 handleClick : function(e){
37799 if(this.hideOnClick){
37800 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37805 expandMenu : function(autoActivate){
37810 hideMenu : function(){
37815 * Ext JS Library 1.1.1
37816 * Copyright(c) 2006-2007, Ext JS, LLC.
37818 * Originally Released Under LGPL - original licence link has changed is not relivant.
37821 * <script type="text/javascript">
37825 * @class Roo.menu.Adapter
37826 * @extends Roo.menu.BaseItem
37827 * 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.
37828 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37830 * Creates a new Adapter
37831 * @param {Object} config Configuration options
37833 Roo.menu.Adapter = function(component, config){
37834 Roo.menu.Adapter.superclass.constructor.call(this, config);
37835 this.component = component;
37837 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37839 canActivate : true,
37842 onRender : function(container, position){
37843 this.component.render(container);
37844 this.el = this.component.getEl();
37848 activate : function(){
37852 this.component.focus();
37853 this.fireEvent("activate", this);
37858 deactivate : function(){
37859 this.fireEvent("deactivate", this);
37863 disable : function(){
37864 this.component.disable();
37865 Roo.menu.Adapter.superclass.disable.call(this);
37869 enable : function(){
37870 this.component.enable();
37871 Roo.menu.Adapter.superclass.enable.call(this);
37875 * Ext JS Library 1.1.1
37876 * Copyright(c) 2006-2007, Ext JS, LLC.
37878 * Originally Released Under LGPL - original licence link has changed is not relivant.
37881 * <script type="text/javascript">
37885 * @class Roo.menu.TextItem
37886 * @extends Roo.menu.BaseItem
37887 * Adds a static text string to a menu, usually used as either a heading or group separator.
37888 * Note: old style constructor with text is still supported.
37891 * Creates a new TextItem
37892 * @param {Object} cfg Configuration
37894 Roo.menu.TextItem = function(cfg){
37895 if (typeof(cfg) == 'string') {
37898 Roo.apply(this,cfg);
37901 Roo.menu.TextItem.superclass.constructor.call(this);
37904 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
37906 * @cfg {Boolean} text Text to show on item.
37911 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
37913 hideOnClick : false,
37915 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
37917 itemCls : "x-menu-text",
37920 onRender : function(){
37921 var s = document.createElement("span");
37922 s.className = this.itemCls;
37923 s.innerHTML = this.text;
37925 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
37929 * Ext JS Library 1.1.1
37930 * Copyright(c) 2006-2007, Ext JS, LLC.
37932 * Originally Released Under LGPL - original licence link has changed is not relivant.
37935 * <script type="text/javascript">
37939 * @class Roo.menu.Separator
37940 * @extends Roo.menu.BaseItem
37941 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
37942 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
37944 * @param {Object} config Configuration options
37946 Roo.menu.Separator = function(config){
37947 Roo.menu.Separator.superclass.constructor.call(this, config);
37950 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
37952 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
37954 itemCls : "x-menu-sep",
37956 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
37958 hideOnClick : false,
37961 onRender : function(li){
37962 var s = document.createElement("span");
37963 s.className = this.itemCls;
37964 s.innerHTML = " ";
37966 li.addClass("x-menu-sep-li");
37967 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
37971 * Ext JS Library 1.1.1
37972 * Copyright(c) 2006-2007, Ext JS, LLC.
37974 * Originally Released Under LGPL - original licence link has changed is not relivant.
37977 * <script type="text/javascript">
37980 * @class Roo.menu.Item
37981 * @extends Roo.menu.BaseItem
37982 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
37983 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
37984 * activation and click handling.
37986 * Creates a new Item
37987 * @param {Object} config Configuration options
37989 Roo.menu.Item = function(config){
37990 Roo.menu.Item.superclass.constructor.call(this, config);
37992 this.menu = Roo.menu.MenuMgr.get(this.menu);
37995 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
37998 * @cfg {String} text
37999 * The text to show on the menu item.
38003 * @cfg {String} HTML to render in menu
38004 * The text to show on the menu item (HTML version).
38008 * @cfg {String} icon
38009 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38013 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38015 itemCls : "x-menu-item",
38017 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38019 canActivate : true,
38021 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38024 // doc'd in BaseItem
38028 ctype: "Roo.menu.Item",
38031 onRender : function(container, position){
38032 var el = document.createElement("a");
38033 el.hideFocus = true;
38034 el.unselectable = "on";
38035 el.href = this.href || "#";
38036 if(this.hrefTarget){
38037 el.target = this.hrefTarget;
38039 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38041 var html = this.html.length ? this.html : String.format('{0}',this.text);
38043 el.innerHTML = String.format(
38044 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38045 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38047 Roo.menu.Item.superclass.onRender.call(this, container, position);
38051 * Sets the text to display in this menu item
38052 * @param {String} text The text to display
38053 * @param {Boolean} isHTML true to indicate text is pure html.
38055 setText : function(text, isHTML){
38063 var html = this.html.length ? this.html : String.format('{0}',this.text);
38065 this.el.update(String.format(
38066 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38067 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38068 this.parentMenu.autoWidth();
38073 handleClick : function(e){
38074 if(!this.href){ // if no link defined, stop the event automatically
38077 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38081 activate : function(autoExpand){
38082 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38092 shouldDeactivate : function(e){
38093 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38094 if(this.menu && this.menu.isVisible()){
38095 return !this.menu.getEl().getRegion().contains(e.getPoint());
38103 deactivate : function(){
38104 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38109 expandMenu : function(autoActivate){
38110 if(!this.disabled && this.menu){
38111 clearTimeout(this.hideTimer);
38112 delete this.hideTimer;
38113 if(!this.menu.isVisible() && !this.showTimer){
38114 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38115 }else if (this.menu.isVisible() && autoActivate){
38116 this.menu.tryActivate(0, 1);
38122 deferExpand : function(autoActivate){
38123 delete this.showTimer;
38124 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38126 this.menu.tryActivate(0, 1);
38131 hideMenu : function(){
38132 clearTimeout(this.showTimer);
38133 delete this.showTimer;
38134 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38135 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38140 deferHide : function(){
38141 delete this.hideTimer;
38146 * Ext JS Library 1.1.1
38147 * Copyright(c) 2006-2007, Ext JS, LLC.
38149 * Originally Released Under LGPL - original licence link has changed is not relivant.
38152 * <script type="text/javascript">
38156 * @class Roo.menu.CheckItem
38157 * @extends Roo.menu.Item
38158 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38160 * Creates a new CheckItem
38161 * @param {Object} config Configuration options
38163 Roo.menu.CheckItem = function(config){
38164 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38167 * @event beforecheckchange
38168 * Fires before the checked value is set, providing an opportunity to cancel if needed
38169 * @param {Roo.menu.CheckItem} this
38170 * @param {Boolean} checked The new checked value that will be set
38172 "beforecheckchange" : true,
38174 * @event checkchange
38175 * Fires after the checked value has been set
38176 * @param {Roo.menu.CheckItem} this
38177 * @param {Boolean} checked The checked value that was set
38179 "checkchange" : true
38181 if(this.checkHandler){
38182 this.on('checkchange', this.checkHandler, this.scope);
38185 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38187 * @cfg {String} group
38188 * All check items with the same group name will automatically be grouped into a single-select
38189 * radio button group (defaults to '')
38192 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38194 itemCls : "x-menu-item x-menu-check-item",
38196 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38198 groupClass : "x-menu-group-item",
38201 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38202 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38203 * initialized with checked = true will be rendered as checked.
38208 ctype: "Roo.menu.CheckItem",
38211 onRender : function(c){
38212 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38214 this.el.addClass(this.groupClass);
38216 Roo.menu.MenuMgr.registerCheckable(this);
38218 this.checked = false;
38219 this.setChecked(true, true);
38224 destroy : function(){
38226 Roo.menu.MenuMgr.unregisterCheckable(this);
38228 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38232 * Set the checked state of this item
38233 * @param {Boolean} checked The new checked value
38234 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38236 setChecked : function(state, suppressEvent){
38237 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38238 if(this.container){
38239 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38241 this.checked = state;
38242 if(suppressEvent !== true){
38243 this.fireEvent("checkchange", this, state);
38249 handleClick : function(e){
38250 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38251 this.setChecked(!this.checked);
38253 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38257 * Ext JS Library 1.1.1
38258 * Copyright(c) 2006-2007, Ext JS, LLC.
38260 * Originally Released Under LGPL - original licence link has changed is not relivant.
38263 * <script type="text/javascript">
38267 * @class Roo.menu.DateItem
38268 * @extends Roo.menu.Adapter
38269 * A menu item that wraps the {@link Roo.DatPicker} component.
38271 * Creates a new DateItem
38272 * @param {Object} config Configuration options
38274 Roo.menu.DateItem = function(config){
38275 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38276 /** The Roo.DatePicker object @type Roo.DatePicker */
38277 this.picker = this.component;
38278 this.addEvents({select: true});
38280 this.picker.on("render", function(picker){
38281 picker.getEl().swallowEvent("click");
38282 picker.container.addClass("x-menu-date-item");
38285 this.picker.on("select", this.onSelect, this);
38288 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38290 onSelect : function(picker, date){
38291 this.fireEvent("select", this, date, picker);
38292 Roo.menu.DateItem.superclass.handleClick.call(this);
38296 * Ext JS Library 1.1.1
38297 * Copyright(c) 2006-2007, Ext JS, LLC.
38299 * Originally Released Under LGPL - original licence link has changed is not relivant.
38302 * <script type="text/javascript">
38306 * @class Roo.menu.ColorItem
38307 * @extends Roo.menu.Adapter
38308 * A menu item that wraps the {@link Roo.ColorPalette} component.
38310 * Creates a new ColorItem
38311 * @param {Object} config Configuration options
38313 Roo.menu.ColorItem = function(config){
38314 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38315 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38316 this.palette = this.component;
38317 this.relayEvents(this.palette, ["select"]);
38318 if(this.selectHandler){
38319 this.on('select', this.selectHandler, this.scope);
38322 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38324 * Ext JS Library 1.1.1
38325 * Copyright(c) 2006-2007, Ext JS, LLC.
38327 * Originally Released Under LGPL - original licence link has changed is not relivant.
38330 * <script type="text/javascript">
38335 * @class Roo.menu.DateMenu
38336 * @extends Roo.menu.Menu
38337 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38339 * Creates a new DateMenu
38340 * @param {Object} config Configuration options
38342 Roo.menu.DateMenu = function(config){
38343 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38345 var di = new Roo.menu.DateItem(config);
38348 * The {@link Roo.DatePicker} instance for this DateMenu
38351 this.picker = di.picker;
38354 * @param {DatePicker} picker
38355 * @param {Date} date
38357 this.relayEvents(di, ["select"]);
38358 this.on('beforeshow', function(){
38360 this.picker.hideMonthPicker(false);
38364 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38368 * Ext JS Library 1.1.1
38369 * Copyright(c) 2006-2007, Ext JS, LLC.
38371 * Originally Released Under LGPL - original licence link has changed is not relivant.
38374 * <script type="text/javascript">
38379 * @class Roo.menu.ColorMenu
38380 * @extends Roo.menu.Menu
38381 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38383 * Creates a new ColorMenu
38384 * @param {Object} config Configuration options
38386 Roo.menu.ColorMenu = function(config){
38387 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38389 var ci = new Roo.menu.ColorItem(config);
38392 * The {@link Roo.ColorPalette} instance for this ColorMenu
38393 * @type ColorPalette
38395 this.palette = ci.palette;
38398 * @param {ColorPalette} palette
38399 * @param {String} color
38401 this.relayEvents(ci, ["select"]);
38403 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38405 * Ext JS Library 1.1.1
38406 * Copyright(c) 2006-2007, Ext JS, LLC.
38408 * Originally Released Under LGPL - original licence link has changed is not relivant.
38411 * <script type="text/javascript">
38415 * @class Roo.form.Field
38416 * @extends Roo.BoxComponent
38417 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38419 * Creates a new Field
38420 * @param {Object} config Configuration options
38422 Roo.form.Field = function(config){
38423 Roo.form.Field.superclass.constructor.call(this, config);
38426 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38428 * @cfg {String} fieldLabel Label to use when rendering a form.
38431 * @cfg {String} qtip Mouse over tip
38435 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38437 invalidClass : "x-form-invalid",
38439 * @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")
38441 invalidText : "The value in this field is invalid",
38443 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38445 focusClass : "x-form-focus",
38447 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38448 automatic validation (defaults to "keyup").
38450 validationEvent : "keyup",
38452 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38454 validateOnBlur : true,
38456 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38458 validationDelay : 250,
38460 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38461 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38463 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38465 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38467 fieldClass : "x-form-field",
38469 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38472 ----------- ----------------------------------------------------------------------
38473 qtip Display a quick tip when the user hovers over the field
38474 title Display a default browser title attribute popup
38475 under Add a block div beneath the field containing the error text
38476 side Add an error icon to the right of the field with a popup on hover
38477 [element id] Add the error text directly to the innerHTML of the specified element
38480 msgTarget : 'qtip',
38482 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38487 * @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.
38492 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38497 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38499 inputType : undefined,
38502 * @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).
38504 tabIndex : undefined,
38507 isFormField : true,
38512 * @property {Roo.Element} fieldEl
38513 * Element Containing the rendered Field (with label etc.)
38516 * @cfg {Mixed} value A value to initialize this field with.
38521 * @cfg {String} name The field's HTML name attribute.
38524 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38527 loadedValue : false,
38531 initComponent : function(){
38532 Roo.form.Field.superclass.initComponent.call(this);
38536 * Fires when this field receives input focus.
38537 * @param {Roo.form.Field} this
38542 * Fires when this field loses input focus.
38543 * @param {Roo.form.Field} this
38547 * @event specialkey
38548 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38549 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38550 * @param {Roo.form.Field} this
38551 * @param {Roo.EventObject} e The event object
38556 * Fires just before the field blurs if the field value has changed.
38557 * @param {Roo.form.Field} this
38558 * @param {Mixed} newValue The new value
38559 * @param {Mixed} oldValue The original value
38564 * Fires after the field has been marked as invalid.
38565 * @param {Roo.form.Field} this
38566 * @param {String} msg The validation message
38571 * Fires after the field has been validated with no errors.
38572 * @param {Roo.form.Field} this
38577 * Fires after the key up
38578 * @param {Roo.form.Field} this
38579 * @param {Roo.EventObject} e The event Object
38586 * Returns the name attribute of the field if available
38587 * @return {String} name The field name
38589 getName: function(){
38590 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38594 onRender : function(ct, position){
38595 Roo.form.Field.superclass.onRender.call(this, ct, position);
38597 var cfg = this.getAutoCreate();
38599 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38601 if (!cfg.name.length) {
38604 if(this.inputType){
38605 cfg.type = this.inputType;
38607 this.el = ct.createChild(cfg, position);
38609 var type = this.el.dom.type;
38611 if(type == 'password'){
38614 this.el.addClass('x-form-'+type);
38617 this.el.dom.readOnly = true;
38619 if(this.tabIndex !== undefined){
38620 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38623 this.el.addClass([this.fieldClass, this.cls]);
38628 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38629 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38630 * @return {Roo.form.Field} this
38632 applyTo : function(target){
38633 this.allowDomMove = false;
38634 this.el = Roo.get(target);
38635 this.render(this.el.dom.parentNode);
38640 initValue : function(){
38641 if(this.value !== undefined){
38642 this.setValue(this.value);
38643 }else if(this.el.dom.value.length > 0){
38644 this.setValue(this.el.dom.value);
38649 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38650 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38652 isDirty : function() {
38653 if(this.disabled) {
38656 return String(this.getValue()) !== String(this.originalValue);
38660 * stores the current value in loadedValue
38662 resetHasChanged : function()
38664 this.loadedValue = String(this.getValue());
38667 * checks the current value against the 'loaded' value.
38668 * Note - will return false if 'resetHasChanged' has not been called first.
38670 hasChanged : function()
38672 if(this.disabled || this.readOnly) {
38675 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38681 afterRender : function(){
38682 Roo.form.Field.superclass.afterRender.call(this);
38687 fireKey : function(e){
38688 //Roo.log('field ' + e.getKey());
38689 if(e.isNavKeyPress()){
38690 this.fireEvent("specialkey", this, e);
38695 * Resets the current field value to the originally loaded value and clears any validation messages
38697 reset : function(){
38698 this.setValue(this.resetValue);
38699 this.clearInvalid();
38703 initEvents : function(){
38704 // safari killled keypress - so keydown is now used..
38705 this.el.on("keydown" , this.fireKey, this);
38706 this.el.on("focus", this.onFocus, this);
38707 this.el.on("blur", this.onBlur, this);
38708 this.el.relayEvent('keyup', this);
38710 // reference to original value for reset
38711 this.originalValue = this.getValue();
38712 this.resetValue = this.getValue();
38716 onFocus : function(){
38717 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38718 this.el.addClass(this.focusClass);
38720 if(!this.hasFocus){
38721 this.hasFocus = true;
38722 this.startValue = this.getValue();
38723 this.fireEvent("focus", this);
38727 beforeBlur : Roo.emptyFn,
38730 onBlur : function(){
38732 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38733 this.el.removeClass(this.focusClass);
38735 this.hasFocus = false;
38736 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38739 var v = this.getValue();
38740 if(String(v) !== String(this.startValue)){
38741 this.fireEvent('change', this, v, this.startValue);
38743 this.fireEvent("blur", this);
38747 * Returns whether or not the field value is currently valid
38748 * @param {Boolean} preventMark True to disable marking the field invalid
38749 * @return {Boolean} True if the value is valid, else false
38751 isValid : function(preventMark){
38755 var restore = this.preventMark;
38756 this.preventMark = preventMark === true;
38757 var v = this.validateValue(this.processValue(this.getRawValue()));
38758 this.preventMark = restore;
38763 * Validates the field value
38764 * @return {Boolean} True if the value is valid, else false
38766 validate : function(){
38767 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38768 this.clearInvalid();
38774 processValue : function(value){
38779 // Subclasses should provide the validation implementation by overriding this
38780 validateValue : function(value){
38785 * Mark this field as invalid
38786 * @param {String} msg The validation message
38788 markInvalid : function(msg){
38789 if(!this.rendered || this.preventMark){ // not rendered
38793 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38795 obj.el.addClass(this.invalidClass);
38796 msg = msg || this.invalidText;
38797 switch(this.msgTarget){
38799 obj.el.dom.qtip = msg;
38800 obj.el.dom.qclass = 'x-form-invalid-tip';
38801 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38802 Roo.QuickTips.enable();
38806 this.el.dom.title = msg;
38810 var elp = this.el.findParent('.x-form-element', 5, true);
38811 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38812 this.errorEl.setWidth(elp.getWidth(true)-20);
38814 this.errorEl.update(msg);
38815 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38818 if(!this.errorIcon){
38819 var elp = this.el.findParent('.x-form-element', 5, true);
38820 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38822 this.alignErrorIcon();
38823 this.errorIcon.dom.qtip = msg;
38824 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38825 this.errorIcon.show();
38826 this.on('resize', this.alignErrorIcon, this);
38829 var t = Roo.getDom(this.msgTarget);
38831 t.style.display = this.msgDisplay;
38834 this.fireEvent('invalid', this, msg);
38838 alignErrorIcon : function(){
38839 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38843 * Clear any invalid styles/messages for this field
38845 clearInvalid : function(){
38846 if(!this.rendered || this.preventMark){ // not rendered
38849 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38851 obj.el.removeClass(this.invalidClass);
38852 switch(this.msgTarget){
38854 obj.el.dom.qtip = '';
38857 this.el.dom.title = '';
38861 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
38865 if(this.errorIcon){
38866 this.errorIcon.dom.qtip = '';
38867 this.errorIcon.hide();
38868 this.un('resize', this.alignErrorIcon, this);
38872 var t = Roo.getDom(this.msgTarget);
38874 t.style.display = 'none';
38877 this.fireEvent('valid', this);
38881 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
38882 * @return {Mixed} value The field value
38884 getRawValue : function(){
38885 var v = this.el.getValue();
38891 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
38892 * @return {Mixed} value The field value
38894 getValue : function(){
38895 var v = this.el.getValue();
38901 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
38902 * @param {Mixed} value The value to set
38904 setRawValue : function(v){
38905 return this.el.dom.value = (v === null || v === undefined ? '' : v);
38909 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
38910 * @param {Mixed} value The value to set
38912 setValue : function(v){
38915 this.el.dom.value = (v === null || v === undefined ? '' : v);
38920 adjustSize : function(w, h){
38921 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
38922 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
38926 adjustWidth : function(tag, w){
38927 tag = tag.toLowerCase();
38928 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
38929 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
38930 if(tag == 'input'){
38933 if(tag == 'textarea'){
38936 }else if(Roo.isOpera){
38937 if(tag == 'input'){
38940 if(tag == 'textarea'){
38950 // anything other than normal should be considered experimental
38951 Roo.form.Field.msgFx = {
38953 show: function(msgEl, f){
38954 msgEl.setDisplayed('block');
38957 hide : function(msgEl, f){
38958 msgEl.setDisplayed(false).update('');
38963 show: function(msgEl, f){
38964 msgEl.slideIn('t', {stopFx:true});
38967 hide : function(msgEl, f){
38968 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
38973 show: function(msgEl, f){
38974 msgEl.fixDisplay();
38975 msgEl.alignTo(f.el, 'tl-tr');
38976 msgEl.slideIn('l', {stopFx:true});
38979 hide : function(msgEl, f){
38980 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
38985 * Ext JS Library 1.1.1
38986 * Copyright(c) 2006-2007, Ext JS, LLC.
38988 * Originally Released Under LGPL - original licence link has changed is not relivant.
38991 * <script type="text/javascript">
38996 * @class Roo.form.TextField
38997 * @extends Roo.form.Field
38998 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
38999 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39001 * Creates a new TextField
39002 * @param {Object} config Configuration options
39004 Roo.form.TextField = function(config){
39005 Roo.form.TextField.superclass.constructor.call(this, config);
39009 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39010 * according to the default logic, but this event provides a hook for the developer to apply additional
39011 * logic at runtime to resize the field if needed.
39012 * @param {Roo.form.Field} this This text field
39013 * @param {Number} width The new field width
39019 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39021 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39025 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39029 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39033 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39037 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39041 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39043 disableKeyFilter : false,
39045 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39049 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39053 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39055 maxLength : Number.MAX_VALUE,
39057 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39059 minLengthText : "The minimum length for this field is {0}",
39061 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39063 maxLengthText : "The maximum length for this field is {0}",
39065 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39067 selectOnFocus : false,
39069 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39071 blankText : "This field is required",
39073 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39074 * If available, this function will be called only after the basic validators all return true, and will be passed the
39075 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39079 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39080 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39081 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39085 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39089 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39095 initEvents : function()
39097 if (this.emptyText) {
39098 this.el.attr('placeholder', this.emptyText);
39101 Roo.form.TextField.superclass.initEvents.call(this);
39102 if(this.validationEvent == 'keyup'){
39103 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39104 this.el.on('keyup', this.filterValidation, this);
39106 else if(this.validationEvent !== false){
39107 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39110 if(this.selectOnFocus){
39111 this.on("focus", this.preFocus, this);
39114 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39115 this.el.on("keypress", this.filterKeys, this);
39118 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39119 this.el.on("click", this.autoSize, this);
39121 if(this.el.is('input[type=password]') && Roo.isSafari){
39122 this.el.on('keydown', this.SafariOnKeyDown, this);
39126 processValue : function(value){
39127 if(this.stripCharsRe){
39128 var newValue = value.replace(this.stripCharsRe, '');
39129 if(newValue !== value){
39130 this.setRawValue(newValue);
39137 filterValidation : function(e){
39138 if(!e.isNavKeyPress()){
39139 this.validationTask.delay(this.validationDelay);
39144 onKeyUp : function(e){
39145 if(!e.isNavKeyPress()){
39151 * Resets the current field value to the originally-loaded value and clears any validation messages.
39154 reset : function(){
39155 Roo.form.TextField.superclass.reset.call(this);
39161 preFocus : function(){
39163 if(this.selectOnFocus){
39164 this.el.dom.select();
39170 filterKeys : function(e){
39171 var k = e.getKey();
39172 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39175 var c = e.getCharCode(), cc = String.fromCharCode(c);
39176 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39179 if(!this.maskRe.test(cc)){
39184 setValue : function(v){
39186 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39192 * Validates a value according to the field's validation rules and marks the field as invalid
39193 * if the validation fails
39194 * @param {Mixed} value The value to validate
39195 * @return {Boolean} True if the value is valid, else false
39197 validateValue : function(value){
39198 if(value.length < 1) { // if it's blank
39199 if(this.allowBlank){
39200 this.clearInvalid();
39203 this.markInvalid(this.blankText);
39207 if(value.length < this.minLength){
39208 this.markInvalid(String.format(this.minLengthText, this.minLength));
39211 if(value.length > this.maxLength){
39212 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39216 var vt = Roo.form.VTypes;
39217 if(!vt[this.vtype](value, this)){
39218 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39222 if(typeof this.validator == "function"){
39223 var msg = this.validator(value);
39225 this.markInvalid(msg);
39229 if(this.regex && !this.regex.test(value)){
39230 this.markInvalid(this.regexText);
39237 * Selects text in this field
39238 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39239 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39241 selectText : function(start, end){
39242 var v = this.getRawValue();
39244 start = start === undefined ? 0 : start;
39245 end = end === undefined ? v.length : end;
39246 var d = this.el.dom;
39247 if(d.setSelectionRange){
39248 d.setSelectionRange(start, end);
39249 }else if(d.createTextRange){
39250 var range = d.createTextRange();
39251 range.moveStart("character", start);
39252 range.moveEnd("character", v.length-end);
39259 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39260 * This only takes effect if grow = true, and fires the autosize event.
39262 autoSize : function(){
39263 if(!this.grow || !this.rendered){
39267 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39270 var v = el.dom.value;
39271 var d = document.createElement('div');
39272 d.appendChild(document.createTextNode(v));
39276 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39277 this.el.setWidth(w);
39278 this.fireEvent("autosize", this, w);
39282 SafariOnKeyDown : function(event)
39284 // this is a workaround for a password hang bug on chrome/ webkit.
39286 var isSelectAll = false;
39288 if(this.el.dom.selectionEnd > 0){
39289 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39291 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39292 event.preventDefault();
39297 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39299 event.preventDefault();
39300 // this is very hacky as keydown always get's upper case.
39302 var cc = String.fromCharCode(event.getCharCode());
39305 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39313 * Ext JS Library 1.1.1
39314 * Copyright(c) 2006-2007, Ext JS, LLC.
39316 * Originally Released Under LGPL - original licence link has changed is not relivant.
39319 * <script type="text/javascript">
39323 * @class Roo.form.Hidden
39324 * @extends Roo.form.TextField
39325 * Simple Hidden element used on forms
39327 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39330 * Creates a new Hidden form element.
39331 * @param {Object} config Configuration options
39336 // easy hidden field...
39337 Roo.form.Hidden = function(config){
39338 Roo.form.Hidden.superclass.constructor.call(this, config);
39341 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39343 inputType: 'hidden',
39346 labelSeparator: '',
39348 itemCls : 'x-form-item-display-none'
39356 * Ext JS Library 1.1.1
39357 * Copyright(c) 2006-2007, Ext JS, LLC.
39359 * Originally Released Under LGPL - original licence link has changed is not relivant.
39362 * <script type="text/javascript">
39366 * @class Roo.form.TriggerField
39367 * @extends Roo.form.TextField
39368 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39369 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39370 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39371 * for which you can provide a custom implementation. For example:
39373 var trigger = new Roo.form.TriggerField();
39374 trigger.onTriggerClick = myTriggerFn;
39375 trigger.applyTo('my-field');
39378 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39379 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39380 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39381 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39383 * Create a new TriggerField.
39384 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39385 * to the base TextField)
39387 Roo.form.TriggerField = function(config){
39388 this.mimicing = false;
39389 Roo.form.TriggerField.superclass.constructor.call(this, config);
39392 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39394 * @cfg {String} triggerClass A CSS class to apply to the trigger
39397 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39398 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39400 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39402 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39406 /** @cfg {Boolean} grow @hide */
39407 /** @cfg {Number} growMin @hide */
39408 /** @cfg {Number} growMax @hide */
39414 autoSize: Roo.emptyFn,
39418 deferHeight : true,
39421 actionMode : 'wrap',
39423 onResize : function(w, h){
39424 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39425 if(typeof w == 'number'){
39426 var x = w - this.trigger.getWidth();
39427 this.el.setWidth(this.adjustWidth('input', x));
39428 this.trigger.setStyle('left', x+'px');
39433 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39436 getResizeEl : function(){
39441 getPositionEl : function(){
39446 alignErrorIcon : function(){
39447 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39451 onRender : function(ct, position){
39452 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39453 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39454 this.trigger = this.wrap.createChild(this.triggerConfig ||
39455 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39456 if(this.hideTrigger){
39457 this.trigger.setDisplayed(false);
39459 this.initTrigger();
39461 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39466 initTrigger : function(){
39467 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39468 this.trigger.addClassOnOver('x-form-trigger-over');
39469 this.trigger.addClassOnClick('x-form-trigger-click');
39473 onDestroy : function(){
39475 this.trigger.removeAllListeners();
39476 this.trigger.remove();
39479 this.wrap.remove();
39481 Roo.form.TriggerField.superclass.onDestroy.call(this);
39485 onFocus : function(){
39486 Roo.form.TriggerField.superclass.onFocus.call(this);
39487 if(!this.mimicing){
39488 this.wrap.addClass('x-trigger-wrap-focus');
39489 this.mimicing = true;
39490 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39491 if(this.monitorTab){
39492 this.el.on("keydown", this.checkTab, this);
39498 checkTab : function(e){
39499 if(e.getKey() == e.TAB){
39500 this.triggerBlur();
39505 onBlur : function(){
39510 mimicBlur : function(e, t){
39511 if(!this.wrap.contains(t) && this.validateBlur()){
39512 this.triggerBlur();
39517 triggerBlur : function(){
39518 this.mimicing = false;
39519 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39520 if(this.monitorTab){
39521 this.el.un("keydown", this.checkTab, this);
39523 this.wrap.removeClass('x-trigger-wrap-focus');
39524 Roo.form.TriggerField.superclass.onBlur.call(this);
39528 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39529 validateBlur : function(e, t){
39534 onDisable : function(){
39535 Roo.form.TriggerField.superclass.onDisable.call(this);
39537 this.wrap.addClass('x-item-disabled');
39542 onEnable : function(){
39543 Roo.form.TriggerField.superclass.onEnable.call(this);
39545 this.wrap.removeClass('x-item-disabled');
39550 onShow : function(){
39551 var ae = this.getActionEl();
39554 ae.dom.style.display = '';
39555 ae.dom.style.visibility = 'visible';
39561 onHide : function(){
39562 var ae = this.getActionEl();
39563 ae.dom.style.display = 'none';
39567 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39568 * by an implementing function.
39570 * @param {EventObject} e
39572 onTriggerClick : Roo.emptyFn
39575 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39576 // to be extended by an implementing class. For an example of implementing this class, see the custom
39577 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39578 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39579 initComponent : function(){
39580 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39582 this.triggerConfig = {
39583 tag:'span', cls:'x-form-twin-triggers', cn:[
39584 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39585 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39589 getTrigger : function(index){
39590 return this.triggers[index];
39593 initTrigger : function(){
39594 var ts = this.trigger.select('.x-form-trigger', true);
39595 this.wrap.setStyle('overflow', 'hidden');
39596 var triggerField = this;
39597 ts.each(function(t, all, index){
39598 t.hide = function(){
39599 var w = triggerField.wrap.getWidth();
39600 this.dom.style.display = 'none';
39601 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39603 t.show = function(){
39604 var w = triggerField.wrap.getWidth();
39605 this.dom.style.display = '';
39606 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39608 var triggerIndex = 'Trigger'+(index+1);
39610 if(this['hide'+triggerIndex]){
39611 t.dom.style.display = 'none';
39613 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39614 t.addClassOnOver('x-form-trigger-over');
39615 t.addClassOnClick('x-form-trigger-click');
39617 this.triggers = ts.elements;
39620 onTrigger1Click : Roo.emptyFn,
39621 onTrigger2Click : Roo.emptyFn
39624 * Ext JS Library 1.1.1
39625 * Copyright(c) 2006-2007, Ext JS, LLC.
39627 * Originally Released Under LGPL - original licence link has changed is not relivant.
39630 * <script type="text/javascript">
39634 * @class Roo.form.TextArea
39635 * @extends Roo.form.TextField
39636 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39637 * support for auto-sizing.
39639 * Creates a new TextArea
39640 * @param {Object} config Configuration options
39642 Roo.form.TextArea = function(config){
39643 Roo.form.TextArea.superclass.constructor.call(this, config);
39644 // these are provided exchanges for backwards compat
39645 // minHeight/maxHeight were replaced by growMin/growMax to be
39646 // compatible with TextField growing config values
39647 if(this.minHeight !== undefined){
39648 this.growMin = this.minHeight;
39650 if(this.maxHeight !== undefined){
39651 this.growMax = this.maxHeight;
39655 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39657 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39661 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39665 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39666 * in the field (equivalent to setting overflow: hidden, defaults to false)
39668 preventScrollbars: false,
39670 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39671 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39675 onRender : function(ct, position){
39677 this.defaultAutoCreate = {
39679 style:"width:300px;height:60px;",
39680 autocomplete: "new-password"
39683 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39685 this.textSizeEl = Roo.DomHelper.append(document.body, {
39686 tag: "pre", cls: "x-form-grow-sizer"
39688 if(this.preventScrollbars){
39689 this.el.setStyle("overflow", "hidden");
39691 this.el.setHeight(this.growMin);
39695 onDestroy : function(){
39696 if(this.textSizeEl){
39697 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39699 Roo.form.TextArea.superclass.onDestroy.call(this);
39703 onKeyUp : function(e){
39704 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39710 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39711 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39713 autoSize : function(){
39714 if(!this.grow || !this.textSizeEl){
39718 var v = el.dom.value;
39719 var ts = this.textSizeEl;
39722 ts.appendChild(document.createTextNode(v));
39725 Roo.fly(ts).setWidth(this.el.getWidth());
39727 v = "  ";
39730 v = v.replace(/\n/g, '<p> </p>');
39732 v += " \n ";
39735 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39736 if(h != this.lastHeight){
39737 this.lastHeight = h;
39738 this.el.setHeight(h);
39739 this.fireEvent("autosize", this, h);
39744 * Ext JS Library 1.1.1
39745 * Copyright(c) 2006-2007, Ext JS, LLC.
39747 * Originally Released Under LGPL - original licence link has changed is not relivant.
39750 * <script type="text/javascript">
39755 * @class Roo.form.NumberField
39756 * @extends Roo.form.TextField
39757 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39759 * Creates a new NumberField
39760 * @param {Object} config Configuration options
39762 Roo.form.NumberField = function(config){
39763 Roo.form.NumberField.superclass.constructor.call(this, config);
39766 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39768 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39770 fieldClass: "x-form-field x-form-num-field",
39772 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39774 allowDecimals : true,
39776 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39778 decimalSeparator : ".",
39780 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39782 decimalPrecision : 2,
39784 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39786 allowNegative : true,
39788 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39790 minValue : Number.NEGATIVE_INFINITY,
39792 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39794 maxValue : Number.MAX_VALUE,
39796 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39798 minText : "The minimum value for this field is {0}",
39800 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39802 maxText : "The maximum value for this field is {0}",
39804 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39805 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39807 nanText : "{0} is not a valid number",
39810 initEvents : function(){
39811 Roo.form.NumberField.superclass.initEvents.call(this);
39812 var allowed = "0123456789";
39813 if(this.allowDecimals){
39814 allowed += this.decimalSeparator;
39816 if(this.allowNegative){
39819 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39820 var keyPress = function(e){
39821 var k = e.getKey();
39822 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39825 var c = e.getCharCode();
39826 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39830 this.el.on("keypress", keyPress, this);
39834 validateValue : function(value){
39835 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39838 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39841 var num = this.parseValue(value);
39843 this.markInvalid(String.format(this.nanText, value));
39846 if(num < this.minValue){
39847 this.markInvalid(String.format(this.minText, this.minValue));
39850 if(num > this.maxValue){
39851 this.markInvalid(String.format(this.maxText, this.maxValue));
39857 getValue : function(){
39858 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
39862 parseValue : function(value){
39863 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
39864 return isNaN(value) ? '' : value;
39868 fixPrecision : function(value){
39869 var nan = isNaN(value);
39870 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
39871 return nan ? '' : value;
39873 return parseFloat(value).toFixed(this.decimalPrecision);
39876 setValue : function(v){
39877 v = this.fixPrecision(v);
39878 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
39882 decimalPrecisionFcn : function(v){
39883 return Math.floor(v);
39886 beforeBlur : function(){
39887 var v = this.parseValue(this.getRawValue());
39894 * Ext JS Library 1.1.1
39895 * Copyright(c) 2006-2007, Ext JS, LLC.
39897 * Originally Released Under LGPL - original licence link has changed is not relivant.
39900 * <script type="text/javascript">
39904 * @class Roo.form.DateField
39905 * @extends Roo.form.TriggerField
39906 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
39908 * Create a new DateField
39909 * @param {Object} config
39911 Roo.form.DateField = function(config){
39912 Roo.form.DateField.superclass.constructor.call(this, config);
39918 * Fires when a date is selected
39919 * @param {Roo.form.DateField} combo This combo box
39920 * @param {Date} date The date selected
39927 if(typeof this.minValue == "string") {
39928 this.minValue = this.parseDate(this.minValue);
39930 if(typeof this.maxValue == "string") {
39931 this.maxValue = this.parseDate(this.maxValue);
39933 this.ddMatch = null;
39934 if(this.disabledDates){
39935 var dd = this.disabledDates;
39937 for(var i = 0; i < dd.length; i++){
39939 if(i != dd.length-1) {
39943 this.ddMatch = new RegExp(re + ")");
39947 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
39949 * @cfg {String} format
39950 * The default date format string which can be overriden for localization support. The format must be
39951 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
39955 * @cfg {String} altFormats
39956 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
39957 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
39959 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
39961 * @cfg {Array} disabledDays
39962 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
39964 disabledDays : null,
39966 * @cfg {String} disabledDaysText
39967 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
39969 disabledDaysText : "Disabled",
39971 * @cfg {Array} disabledDates
39972 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
39973 * expression so they are very powerful. Some examples:
39975 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
39976 * <li>["03/08", "09/16"] would disable those days for every year</li>
39977 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
39978 * <li>["03/../2006"] would disable every day in March 2006</li>
39979 * <li>["^03"] would disable every day in every March</li>
39981 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
39982 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
39984 disabledDates : null,
39986 * @cfg {String} disabledDatesText
39987 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
39989 disabledDatesText : "Disabled",
39991 * @cfg {Date/String} minValue
39992 * The minimum allowed date. Can be either a Javascript date object or a string date in a
39993 * valid format (defaults to null).
39997 * @cfg {Date/String} maxValue
39998 * The maximum allowed date. Can be either a Javascript date object or a string date in a
39999 * valid format (defaults to null).
40003 * @cfg {String} minText
40004 * The error text to display when the date in the cell is before minValue (defaults to
40005 * 'The date in this field must be after {minValue}').
40007 minText : "The date in this field must be equal to or after {0}",
40009 * @cfg {String} maxText
40010 * The error text to display when the date in the cell is after maxValue (defaults to
40011 * 'The date in this field must be before {maxValue}').
40013 maxText : "The date in this field must be equal to or before {0}",
40015 * @cfg {String} invalidText
40016 * The error text to display when the date in the field is invalid (defaults to
40017 * '{value} is not a valid date - it must be in the format {format}').
40019 invalidText : "{0} is not a valid date - it must be in the format {1}",
40021 * @cfg {String} triggerClass
40022 * An additional CSS class used to style the trigger button. The trigger will always get the
40023 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40024 * which displays a calendar icon).
40026 triggerClass : 'x-form-date-trigger',
40030 * @cfg {Boolean} useIso
40031 * if enabled, then the date field will use a hidden field to store the
40032 * real value as iso formated date. default (false)
40036 * @cfg {String/Object} autoCreate
40037 * A DomHelper element spec, or true for a default element spec (defaults to
40038 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40041 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40044 hiddenField: false,
40046 onRender : function(ct, position)
40048 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40050 //this.el.dom.removeAttribute('name');
40051 Roo.log("Changing name?");
40052 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40053 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40055 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40056 // prevent input submission
40057 this.hiddenName = this.name;
40064 validateValue : function(value)
40066 value = this.formatDate(value);
40067 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40068 Roo.log('super failed');
40071 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40074 var svalue = value;
40075 value = this.parseDate(value);
40077 Roo.log('parse date failed' + svalue);
40078 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40081 var time = value.getTime();
40082 if(this.minValue && time < this.minValue.getTime()){
40083 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40086 if(this.maxValue && time > this.maxValue.getTime()){
40087 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40090 if(this.disabledDays){
40091 var day = value.getDay();
40092 for(var i = 0; i < this.disabledDays.length; i++) {
40093 if(day === this.disabledDays[i]){
40094 this.markInvalid(this.disabledDaysText);
40099 var fvalue = this.formatDate(value);
40100 if(this.ddMatch && this.ddMatch.test(fvalue)){
40101 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40108 // Provides logic to override the default TriggerField.validateBlur which just returns true
40109 validateBlur : function(){
40110 return !this.menu || !this.menu.isVisible();
40113 getName: function()
40115 // returns hidden if it's set..
40116 if (!this.rendered) {return ''};
40117 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40122 * Returns the current date value of the date field.
40123 * @return {Date} The date value
40125 getValue : function(){
40127 return this.hiddenField ?
40128 this.hiddenField.value :
40129 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40133 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40134 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40135 * (the default format used is "m/d/y").
40138 //All of these calls set the same date value (May 4, 2006)
40140 //Pass a date object:
40141 var dt = new Date('5/4/06');
40142 dateField.setValue(dt);
40144 //Pass a date string (default format):
40145 dateField.setValue('5/4/06');
40147 //Pass a date string (custom format):
40148 dateField.format = 'Y-m-d';
40149 dateField.setValue('2006-5-4');
40151 * @param {String/Date} date The date or valid date string
40153 setValue : function(date){
40154 if (this.hiddenField) {
40155 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40157 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40158 // make sure the value field is always stored as a date..
40159 this.value = this.parseDate(date);
40165 parseDate : function(value){
40166 if(!value || value instanceof Date){
40169 var v = Date.parseDate(value, this.format);
40170 if (!v && this.useIso) {
40171 v = Date.parseDate(value, 'Y-m-d');
40173 if(!v && this.altFormats){
40174 if(!this.altFormatsArray){
40175 this.altFormatsArray = this.altFormats.split("|");
40177 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40178 v = Date.parseDate(value, this.altFormatsArray[i]);
40185 formatDate : function(date, fmt){
40186 return (!date || !(date instanceof Date)) ?
40187 date : date.dateFormat(fmt || this.format);
40192 select: function(m, d){
40195 this.fireEvent('select', this, d);
40197 show : function(){ // retain focus styling
40201 this.focus.defer(10, this);
40202 var ml = this.menuListeners;
40203 this.menu.un("select", ml.select, this);
40204 this.menu.un("show", ml.show, this);
40205 this.menu.un("hide", ml.hide, this);
40210 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40211 onTriggerClick : function(){
40215 if(this.menu == null){
40216 this.menu = new Roo.menu.DateMenu();
40218 Roo.apply(this.menu.picker, {
40219 showClear: this.allowBlank,
40220 minDate : this.minValue,
40221 maxDate : this.maxValue,
40222 disabledDatesRE : this.ddMatch,
40223 disabledDatesText : this.disabledDatesText,
40224 disabledDays : this.disabledDays,
40225 disabledDaysText : this.disabledDaysText,
40226 format : this.useIso ? 'Y-m-d' : this.format,
40227 minText : String.format(this.minText, this.formatDate(this.minValue)),
40228 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40230 this.menu.on(Roo.apply({}, this.menuListeners, {
40233 this.menu.picker.setValue(this.getValue() || new Date());
40234 this.menu.show(this.el, "tl-bl?");
40237 beforeBlur : function(){
40238 var v = this.parseDate(this.getRawValue());
40248 isDirty : function() {
40249 if(this.disabled) {
40253 if(typeof(this.startValue) === 'undefined'){
40257 return String(this.getValue()) !== String(this.startValue);
40262 * Ext JS Library 1.1.1
40263 * Copyright(c) 2006-2007, Ext JS, LLC.
40265 * Originally Released Under LGPL - original licence link has changed is not relivant.
40268 * <script type="text/javascript">
40272 * @class Roo.form.MonthField
40273 * @extends Roo.form.TriggerField
40274 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40276 * Create a new MonthField
40277 * @param {Object} config
40279 Roo.form.MonthField = function(config){
40281 Roo.form.MonthField.superclass.constructor.call(this, config);
40287 * Fires when a date is selected
40288 * @param {Roo.form.MonthFieeld} combo This combo box
40289 * @param {Date} date The date selected
40296 if(typeof this.minValue == "string") {
40297 this.minValue = this.parseDate(this.minValue);
40299 if(typeof this.maxValue == "string") {
40300 this.maxValue = this.parseDate(this.maxValue);
40302 this.ddMatch = null;
40303 if(this.disabledDates){
40304 var dd = this.disabledDates;
40306 for(var i = 0; i < dd.length; i++){
40308 if(i != dd.length-1) {
40312 this.ddMatch = new RegExp(re + ")");
40316 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40318 * @cfg {String} format
40319 * The default date format string which can be overriden for localization support. The format must be
40320 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40324 * @cfg {String} altFormats
40325 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40326 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40328 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40330 * @cfg {Array} disabledDays
40331 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40333 disabledDays : [0,1,2,3,4,5,6],
40335 * @cfg {String} disabledDaysText
40336 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40338 disabledDaysText : "Disabled",
40340 * @cfg {Array} disabledDates
40341 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40342 * expression so they are very powerful. Some examples:
40344 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40345 * <li>["03/08", "09/16"] would disable those days for every year</li>
40346 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40347 * <li>["03/../2006"] would disable every day in March 2006</li>
40348 * <li>["^03"] would disable every day in every March</li>
40350 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40351 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40353 disabledDates : null,
40355 * @cfg {String} disabledDatesText
40356 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40358 disabledDatesText : "Disabled",
40360 * @cfg {Date/String} minValue
40361 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40362 * valid format (defaults to null).
40366 * @cfg {Date/String} maxValue
40367 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40368 * valid format (defaults to null).
40372 * @cfg {String} minText
40373 * The error text to display when the date in the cell is before minValue (defaults to
40374 * 'The date in this field must be after {minValue}').
40376 minText : "The date in this field must be equal to or after {0}",
40378 * @cfg {String} maxTextf
40379 * The error text to display when the date in the cell is after maxValue (defaults to
40380 * 'The date in this field must be before {maxValue}').
40382 maxText : "The date in this field must be equal to or before {0}",
40384 * @cfg {String} invalidText
40385 * The error text to display when the date in the field is invalid (defaults to
40386 * '{value} is not a valid date - it must be in the format {format}').
40388 invalidText : "{0} is not a valid date - it must be in the format {1}",
40390 * @cfg {String} triggerClass
40391 * An additional CSS class used to style the trigger button. The trigger will always get the
40392 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40393 * which displays a calendar icon).
40395 triggerClass : 'x-form-date-trigger',
40399 * @cfg {Boolean} useIso
40400 * if enabled, then the date field will use a hidden field to store the
40401 * real value as iso formated date. default (true)
40405 * @cfg {String/Object} autoCreate
40406 * A DomHelper element spec, or true for a default element spec (defaults to
40407 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40410 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40413 hiddenField: false,
40415 hideMonthPicker : false,
40417 onRender : function(ct, position)
40419 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40421 this.el.dom.removeAttribute('name');
40422 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40424 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40425 // prevent input submission
40426 this.hiddenName = this.name;
40433 validateValue : function(value)
40435 value = this.formatDate(value);
40436 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40439 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40442 var svalue = value;
40443 value = this.parseDate(value);
40445 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40448 var time = value.getTime();
40449 if(this.minValue && time < this.minValue.getTime()){
40450 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40453 if(this.maxValue && time > this.maxValue.getTime()){
40454 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40457 /*if(this.disabledDays){
40458 var day = value.getDay();
40459 for(var i = 0; i < this.disabledDays.length; i++) {
40460 if(day === this.disabledDays[i]){
40461 this.markInvalid(this.disabledDaysText);
40467 var fvalue = this.formatDate(value);
40468 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40469 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40477 // Provides logic to override the default TriggerField.validateBlur which just returns true
40478 validateBlur : function(){
40479 return !this.menu || !this.menu.isVisible();
40483 * Returns the current date value of the date field.
40484 * @return {Date} The date value
40486 getValue : function(){
40490 return this.hiddenField ?
40491 this.hiddenField.value :
40492 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40496 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40497 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40498 * (the default format used is "m/d/y").
40501 //All of these calls set the same date value (May 4, 2006)
40503 //Pass a date object:
40504 var dt = new Date('5/4/06');
40505 monthField.setValue(dt);
40507 //Pass a date string (default format):
40508 monthField.setValue('5/4/06');
40510 //Pass a date string (custom format):
40511 monthField.format = 'Y-m-d';
40512 monthField.setValue('2006-5-4');
40514 * @param {String/Date} date The date or valid date string
40516 setValue : function(date){
40517 Roo.log('month setValue' + date);
40518 // can only be first of month..
40520 var val = this.parseDate(date);
40522 if (this.hiddenField) {
40523 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40525 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40526 this.value = this.parseDate(date);
40530 parseDate : function(value){
40531 if(!value || value instanceof Date){
40532 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40535 var v = Date.parseDate(value, this.format);
40536 if (!v && this.useIso) {
40537 v = Date.parseDate(value, 'Y-m-d');
40541 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40545 if(!v && this.altFormats){
40546 if(!this.altFormatsArray){
40547 this.altFormatsArray = this.altFormats.split("|");
40549 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40550 v = Date.parseDate(value, this.altFormatsArray[i]);
40557 formatDate : function(date, fmt){
40558 return (!date || !(date instanceof Date)) ?
40559 date : date.dateFormat(fmt || this.format);
40564 select: function(m, d){
40566 this.fireEvent('select', this, d);
40568 show : function(){ // retain focus styling
40572 this.focus.defer(10, this);
40573 var ml = this.menuListeners;
40574 this.menu.un("select", ml.select, this);
40575 this.menu.un("show", ml.show, this);
40576 this.menu.un("hide", ml.hide, this);
40580 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40581 onTriggerClick : function(){
40585 if(this.menu == null){
40586 this.menu = new Roo.menu.DateMenu();
40590 Roo.apply(this.menu.picker, {
40592 showClear: this.allowBlank,
40593 minDate : this.minValue,
40594 maxDate : this.maxValue,
40595 disabledDatesRE : this.ddMatch,
40596 disabledDatesText : this.disabledDatesText,
40598 format : this.useIso ? 'Y-m-d' : this.format,
40599 minText : String.format(this.minText, this.formatDate(this.minValue)),
40600 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40603 this.menu.on(Roo.apply({}, this.menuListeners, {
40611 // hide month picker get's called when we called by 'before hide';
40613 var ignorehide = true;
40614 p.hideMonthPicker = function(disableAnim){
40618 if(this.monthPicker){
40619 Roo.log("hideMonthPicker called");
40620 if(disableAnim === true){
40621 this.monthPicker.hide();
40623 this.monthPicker.slideOut('t', {duration:.2});
40624 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40625 p.fireEvent("select", this, this.value);
40631 Roo.log('picker set value');
40632 Roo.log(this.getValue());
40633 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40634 m.show(this.el, 'tl-bl?');
40635 ignorehide = false;
40636 // this will trigger hideMonthPicker..
40639 // hidden the day picker
40640 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40646 p.showMonthPicker.defer(100, p);
40652 beforeBlur : function(){
40653 var v = this.parseDate(this.getRawValue());
40659 /** @cfg {Boolean} grow @hide */
40660 /** @cfg {Number} growMin @hide */
40661 /** @cfg {Number} growMax @hide */
40668 * Ext JS Library 1.1.1
40669 * Copyright(c) 2006-2007, Ext JS, LLC.
40671 * Originally Released Under LGPL - original licence link has changed is not relivant.
40674 * <script type="text/javascript">
40679 * @class Roo.form.ComboBox
40680 * @extends Roo.form.TriggerField
40681 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40683 * Create a new ComboBox.
40684 * @param {Object} config Configuration options
40686 Roo.form.ComboBox = function(config){
40687 Roo.form.ComboBox.superclass.constructor.call(this, config);
40691 * Fires when the dropdown list is expanded
40692 * @param {Roo.form.ComboBox} combo This combo box
40697 * Fires when the dropdown list is collapsed
40698 * @param {Roo.form.ComboBox} combo This combo box
40702 * @event beforeselect
40703 * Fires before a list item is selected. Return false to cancel the selection.
40704 * @param {Roo.form.ComboBox} combo This combo box
40705 * @param {Roo.data.Record} record The data record returned from the underlying store
40706 * @param {Number} index The index of the selected item in the dropdown list
40708 'beforeselect' : true,
40711 * Fires when a list item is selected
40712 * @param {Roo.form.ComboBox} combo This combo box
40713 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40714 * @param {Number} index The index of the selected item in the dropdown list
40718 * @event beforequery
40719 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40720 * The event object passed has these properties:
40721 * @param {Roo.form.ComboBox} combo This combo box
40722 * @param {String} query The query
40723 * @param {Boolean} forceAll true to force "all" query
40724 * @param {Boolean} cancel true to cancel the query
40725 * @param {Object} e The query event object
40727 'beforequery': true,
40730 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40731 * @param {Roo.form.ComboBox} combo This combo box
40736 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40737 * @param {Roo.form.ComboBox} combo This combo box
40738 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40744 if(this.transform){
40745 this.allowDomMove = false;
40746 var s = Roo.getDom(this.transform);
40747 if(!this.hiddenName){
40748 this.hiddenName = s.name;
40751 this.mode = 'local';
40752 var d = [], opts = s.options;
40753 for(var i = 0, len = opts.length;i < len; i++){
40755 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40757 this.value = value;
40759 d.push([value, o.text]);
40761 this.store = new Roo.data.SimpleStore({
40763 fields: ['value', 'text'],
40766 this.valueField = 'value';
40767 this.displayField = 'text';
40769 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40770 if(!this.lazyRender){
40771 this.target = true;
40772 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40773 s.parentNode.removeChild(s); // remove it
40774 this.render(this.el.parentNode);
40776 s.parentNode.removeChild(s); // remove it
40781 this.store = Roo.factory(this.store, Roo.data);
40784 this.selectedIndex = -1;
40785 if(this.mode == 'local'){
40786 if(config.queryDelay === undefined){
40787 this.queryDelay = 10;
40789 if(config.minChars === undefined){
40795 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40797 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40800 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40801 * rendering into an Roo.Editor, defaults to false)
40804 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40805 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40808 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40811 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40812 * the dropdown list (defaults to undefined, with no header element)
40816 * @cfg {String/Roo.Template} tpl The template to use to render the output
40820 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40822 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40824 listWidth: undefined,
40826 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40827 * mode = 'remote' or 'text' if mode = 'local')
40829 displayField: undefined,
40831 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40832 * mode = 'remote' or 'value' if mode = 'local').
40833 * Note: use of a valueField requires the user make a selection
40834 * in order for a value to be mapped.
40836 valueField: undefined,
40840 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40841 * field's data value (defaults to the underlying DOM element's name)
40843 hiddenName: undefined,
40845 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40849 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40851 selectedClass: 'x-combo-selected',
40853 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40854 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40855 * which displays a downward arrow icon).
40857 triggerClass : 'x-form-arrow-trigger',
40859 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
40863 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
40864 * anchor positions (defaults to 'tl-bl')
40866 listAlign: 'tl-bl?',
40868 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
40872 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
40873 * query specified by the allQuery config option (defaults to 'query')
40875 triggerAction: 'query',
40877 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
40878 * (defaults to 4, does not apply if editable = false)
40882 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
40883 * delay (typeAheadDelay) if it matches a known value (defaults to false)
40887 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
40888 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
40892 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
40893 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
40897 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
40898 * when editable = true (defaults to false)
40900 selectOnFocus:false,
40902 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
40904 queryParam: 'query',
40906 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
40907 * when mode = 'remote' (defaults to 'Loading...')
40909 loadingText: 'Loading...',
40911 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
40915 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
40919 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
40920 * traditional select (defaults to true)
40924 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
40928 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
40932 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
40933 * listWidth has a higher value)
40937 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
40938 * allow the user to set arbitrary text into the field (defaults to false)
40940 forceSelection:false,
40942 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
40943 * if typeAhead = true (defaults to 250)
40945 typeAheadDelay : 250,
40947 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
40948 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
40950 valueNotFoundText : undefined,
40952 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
40954 blockFocus : false,
40957 * @cfg {Boolean} disableClear Disable showing of clear button.
40959 disableClear : false,
40961 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
40963 alwaysQuery : false,
40969 // element that contains real text value.. (when hidden is used..)
40972 onRender : function(ct, position){
40973 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
40974 if(this.hiddenName){
40975 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
40977 this.hiddenField.value =
40978 this.hiddenValue !== undefined ? this.hiddenValue :
40979 this.value !== undefined ? this.value : '';
40981 // prevent input submission
40982 this.el.dom.removeAttribute('name');
40987 this.el.dom.setAttribute('autocomplete', 'off');
40990 var cls = 'x-combo-list';
40992 this.list = new Roo.Layer({
40993 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
40996 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
40997 this.list.setWidth(lw);
40998 this.list.swallowEvent('mousewheel');
40999 this.assetHeight = 0;
41002 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41003 this.assetHeight += this.header.getHeight();
41006 this.innerList = this.list.createChild({cls:cls+'-inner'});
41007 this.innerList.on('mouseover', this.onViewOver, this);
41008 this.innerList.on('mousemove', this.onViewMove, this);
41009 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41011 if(this.allowBlank && !this.pageSize && !this.disableClear){
41012 this.footer = this.list.createChild({cls:cls+'-ft'});
41013 this.pageTb = new Roo.Toolbar(this.footer);
41017 this.footer = this.list.createChild({cls:cls+'-ft'});
41018 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41019 {pageSize: this.pageSize});
41023 if (this.pageTb && this.allowBlank && !this.disableClear) {
41025 this.pageTb.add(new Roo.Toolbar.Fill(), {
41026 cls: 'x-btn-icon x-btn-clear',
41028 handler: function()
41031 _this.clearValue();
41032 _this.onSelect(false, -1);
41037 this.assetHeight += this.footer.getHeight();
41042 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41045 this.view = new Roo.View(this.innerList, this.tpl, {
41046 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41049 this.view.on('click', this.onViewClick, this);
41051 this.store.on('beforeload', this.onBeforeLoad, this);
41052 this.store.on('load', this.onLoad, this);
41053 this.store.on('loadexception', this.onLoadException, this);
41055 if(this.resizable){
41056 this.resizer = new Roo.Resizable(this.list, {
41057 pinned:true, handles:'se'
41059 this.resizer.on('resize', function(r, w, h){
41060 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41061 this.listWidth = w;
41062 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41063 this.restrictHeight();
41065 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41067 if(!this.editable){
41068 this.editable = true;
41069 this.setEditable(false);
41073 if (typeof(this.events.add.listeners) != 'undefined') {
41075 this.addicon = this.wrap.createChild(
41076 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41078 this.addicon.on('click', function(e) {
41079 this.fireEvent('add', this);
41082 if (typeof(this.events.edit.listeners) != 'undefined') {
41084 this.editicon = this.wrap.createChild(
41085 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41086 if (this.addicon) {
41087 this.editicon.setStyle('margin-left', '40px');
41089 this.editicon.on('click', function(e) {
41091 // we fire even if inothing is selected..
41092 this.fireEvent('edit', this, this.lastData );
41102 initEvents : function(){
41103 Roo.form.ComboBox.superclass.initEvents.call(this);
41105 this.keyNav = new Roo.KeyNav(this.el, {
41106 "up" : function(e){
41107 this.inKeyMode = true;
41111 "down" : function(e){
41112 if(!this.isExpanded()){
41113 this.onTriggerClick();
41115 this.inKeyMode = true;
41120 "enter" : function(e){
41121 this.onViewClick();
41125 "esc" : function(e){
41129 "tab" : function(e){
41130 this.onViewClick(false);
41131 this.fireEvent("specialkey", this, e);
41137 doRelay : function(foo, bar, hname){
41138 if(hname == 'down' || this.scope.isExpanded()){
41139 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41146 this.queryDelay = Math.max(this.queryDelay || 10,
41147 this.mode == 'local' ? 10 : 250);
41148 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41149 if(this.typeAhead){
41150 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41152 if(this.editable !== false){
41153 this.el.on("keyup", this.onKeyUp, this);
41155 if(this.forceSelection){
41156 this.on('blur', this.doForce, this);
41160 onDestroy : function(){
41162 this.view.setStore(null);
41163 this.view.el.removeAllListeners();
41164 this.view.el.remove();
41165 this.view.purgeListeners();
41168 this.list.destroy();
41171 this.store.un('beforeload', this.onBeforeLoad, this);
41172 this.store.un('load', this.onLoad, this);
41173 this.store.un('loadexception', this.onLoadException, this);
41175 Roo.form.ComboBox.superclass.onDestroy.call(this);
41179 fireKey : function(e){
41180 if(e.isNavKeyPress() && !this.list.isVisible()){
41181 this.fireEvent("specialkey", this, e);
41186 onResize: function(w, h){
41187 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41189 if(typeof w != 'number'){
41190 // we do not handle it!?!?
41193 var tw = this.trigger.getWidth();
41194 tw += this.addicon ? this.addicon.getWidth() : 0;
41195 tw += this.editicon ? this.editicon.getWidth() : 0;
41197 this.el.setWidth( this.adjustWidth('input', x));
41199 this.trigger.setStyle('left', x+'px');
41201 if(this.list && this.listWidth === undefined){
41202 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41203 this.list.setWidth(lw);
41204 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41212 * Allow or prevent the user from directly editing the field text. If false is passed,
41213 * the user will only be able to select from the items defined in the dropdown list. This method
41214 * is the runtime equivalent of setting the 'editable' config option at config time.
41215 * @param {Boolean} value True to allow the user to directly edit the field text
41217 setEditable : function(value){
41218 if(value == this.editable){
41221 this.editable = value;
41223 this.el.dom.setAttribute('readOnly', true);
41224 this.el.on('mousedown', this.onTriggerClick, this);
41225 this.el.addClass('x-combo-noedit');
41227 this.el.dom.setAttribute('readOnly', false);
41228 this.el.un('mousedown', this.onTriggerClick, this);
41229 this.el.removeClass('x-combo-noedit');
41234 onBeforeLoad : function(){
41235 if(!this.hasFocus){
41238 this.innerList.update(this.loadingText ?
41239 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41240 this.restrictHeight();
41241 this.selectedIndex = -1;
41245 onLoad : function(){
41246 if(!this.hasFocus){
41249 if(this.store.getCount() > 0){
41251 this.restrictHeight();
41252 if(this.lastQuery == this.allQuery){
41254 this.el.dom.select();
41256 if(!this.selectByValue(this.value, true)){
41257 this.select(0, true);
41261 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41262 this.taTask.delay(this.typeAheadDelay);
41266 this.onEmptyResults();
41271 onLoadException : function()
41274 Roo.log(this.store.reader.jsonData);
41275 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41276 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41282 onTypeAhead : function(){
41283 if(this.store.getCount() > 0){
41284 var r = this.store.getAt(0);
41285 var newValue = r.data[this.displayField];
41286 var len = newValue.length;
41287 var selStart = this.getRawValue().length;
41288 if(selStart != len){
41289 this.setRawValue(newValue);
41290 this.selectText(selStart, newValue.length);
41296 onSelect : function(record, index){
41297 if(this.fireEvent('beforeselect', this, record, index) !== false){
41298 this.setFromData(index > -1 ? record.data : false);
41300 this.fireEvent('select', this, record, index);
41305 * Returns the currently selected field value or empty string if no value is set.
41306 * @return {String} value The selected value
41308 getValue : function(){
41309 if(this.valueField){
41310 return typeof this.value != 'undefined' ? this.value : '';
41312 return Roo.form.ComboBox.superclass.getValue.call(this);
41316 * Clears any text/value currently set in the field
41318 clearValue : function(){
41319 if(this.hiddenField){
41320 this.hiddenField.value = '';
41323 this.setRawValue('');
41324 this.lastSelectionText = '';
41329 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41330 * will be displayed in the field. If the value does not match the data value of an existing item,
41331 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41332 * Otherwise the field will be blank (although the value will still be set).
41333 * @param {String} value The value to match
41335 setValue : function(v){
41337 if(this.valueField){
41338 var r = this.findRecord(this.valueField, v);
41340 text = r.data[this.displayField];
41341 }else if(this.valueNotFoundText !== undefined){
41342 text = this.valueNotFoundText;
41345 this.lastSelectionText = text;
41346 if(this.hiddenField){
41347 this.hiddenField.value = v;
41349 Roo.form.ComboBox.superclass.setValue.call(this, text);
41353 * @property {Object} the last set data for the element
41358 * Sets the value of the field based on a object which is related to the record format for the store.
41359 * @param {Object} value the value to set as. or false on reset?
41361 setFromData : function(o){
41362 var dv = ''; // display value
41363 var vv = ''; // value value..
41365 if (this.displayField) {
41366 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41368 // this is an error condition!!!
41369 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41372 if(this.valueField){
41373 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41375 if(this.hiddenField){
41376 this.hiddenField.value = vv;
41378 this.lastSelectionText = dv;
41379 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41383 // no hidden field.. - we store the value in 'value', but still display
41384 // display field!!!!
41385 this.lastSelectionText = dv;
41386 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41392 reset : function(){
41393 // overridden so that last data is reset..
41394 this.setValue(this.resetValue);
41395 this.clearInvalid();
41396 this.lastData = false;
41398 this.view.clearSelections();
41402 findRecord : function(prop, value){
41404 if(this.store.getCount() > 0){
41405 this.store.each(function(r){
41406 if(r.data[prop] == value){
41416 getName: function()
41418 // returns hidden if it's set..
41419 if (!this.rendered) {return ''};
41420 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41424 onViewMove : function(e, t){
41425 this.inKeyMode = false;
41429 onViewOver : function(e, t){
41430 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41433 var item = this.view.findItemFromChild(t);
41435 var index = this.view.indexOf(item);
41436 this.select(index, false);
41441 onViewClick : function(doFocus)
41443 var index = this.view.getSelectedIndexes()[0];
41444 var r = this.store.getAt(index);
41446 this.onSelect(r, index);
41448 if(doFocus !== false && !this.blockFocus){
41454 restrictHeight : function(){
41455 this.innerList.dom.style.height = '';
41456 var inner = this.innerList.dom;
41457 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41458 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41459 this.list.beginUpdate();
41460 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41461 this.list.alignTo(this.el, this.listAlign);
41462 this.list.endUpdate();
41466 onEmptyResults : function(){
41471 * Returns true if the dropdown list is expanded, else false.
41473 isExpanded : function(){
41474 return this.list.isVisible();
41478 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41479 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41480 * @param {String} value The data value of the item to select
41481 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41482 * selected item if it is not currently in view (defaults to true)
41483 * @return {Boolean} True if the value matched an item in the list, else false
41485 selectByValue : function(v, scrollIntoView){
41486 if(v !== undefined && v !== null){
41487 var r = this.findRecord(this.valueField || this.displayField, v);
41489 this.select(this.store.indexOf(r), scrollIntoView);
41497 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41498 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41499 * @param {Number} index The zero-based index of the list item to select
41500 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41501 * selected item if it is not currently in view (defaults to true)
41503 select : function(index, scrollIntoView){
41504 this.selectedIndex = index;
41505 this.view.select(index);
41506 if(scrollIntoView !== false){
41507 var el = this.view.getNode(index);
41509 this.innerList.scrollChildIntoView(el, false);
41515 selectNext : function(){
41516 var ct = this.store.getCount();
41518 if(this.selectedIndex == -1){
41520 }else if(this.selectedIndex < ct-1){
41521 this.select(this.selectedIndex+1);
41527 selectPrev : function(){
41528 var ct = this.store.getCount();
41530 if(this.selectedIndex == -1){
41532 }else if(this.selectedIndex != 0){
41533 this.select(this.selectedIndex-1);
41539 onKeyUp : function(e){
41540 if(this.editable !== false && !e.isSpecialKey()){
41541 this.lastKey = e.getKey();
41542 this.dqTask.delay(this.queryDelay);
41547 validateBlur : function(){
41548 return !this.list || !this.list.isVisible();
41552 initQuery : function(){
41553 this.doQuery(this.getRawValue());
41557 doForce : function(){
41558 if(this.el.dom.value.length > 0){
41559 this.el.dom.value =
41560 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41566 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41567 * query allowing the query action to be canceled if needed.
41568 * @param {String} query The SQL query to execute
41569 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41570 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41571 * saved in the current store (defaults to false)
41573 doQuery : function(q, forceAll){
41574 if(q === undefined || q === null){
41579 forceAll: forceAll,
41583 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41587 forceAll = qe.forceAll;
41588 if(forceAll === true || (q.length >= this.minChars)){
41589 if(this.lastQuery != q || this.alwaysQuery){
41590 this.lastQuery = q;
41591 if(this.mode == 'local'){
41592 this.selectedIndex = -1;
41594 this.store.clearFilter();
41596 this.store.filter(this.displayField, q);
41600 this.store.baseParams[this.queryParam] = q;
41602 params: this.getParams(q)
41607 this.selectedIndex = -1;
41614 getParams : function(q){
41616 //p[this.queryParam] = q;
41619 p.limit = this.pageSize;
41625 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41627 collapse : function(){
41628 if(!this.isExpanded()){
41632 Roo.get(document).un('mousedown', this.collapseIf, this);
41633 Roo.get(document).un('mousewheel', this.collapseIf, this);
41634 if (!this.editable) {
41635 Roo.get(document).un('keydown', this.listKeyPress, this);
41637 this.fireEvent('collapse', this);
41641 collapseIf : function(e){
41642 if(!e.within(this.wrap) && !e.within(this.list)){
41648 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41650 expand : function(){
41651 if(this.isExpanded() || !this.hasFocus){
41654 this.list.alignTo(this.el, this.listAlign);
41656 Roo.get(document).on('mousedown', this.collapseIf, this);
41657 Roo.get(document).on('mousewheel', this.collapseIf, this);
41658 if (!this.editable) {
41659 Roo.get(document).on('keydown', this.listKeyPress, this);
41662 this.fireEvent('expand', this);
41666 // Implements the default empty TriggerField.onTriggerClick function
41667 onTriggerClick : function(){
41671 if(this.isExpanded()){
41673 if (!this.blockFocus) {
41678 this.hasFocus = true;
41679 if(this.triggerAction == 'all') {
41680 this.doQuery(this.allQuery, true);
41682 this.doQuery(this.getRawValue());
41684 if (!this.blockFocus) {
41689 listKeyPress : function(e)
41691 //Roo.log('listkeypress');
41692 // scroll to first matching element based on key pres..
41693 if (e.isSpecialKey()) {
41696 var k = String.fromCharCode(e.getKey()).toUpperCase();
41699 var csel = this.view.getSelectedNodes();
41700 var cselitem = false;
41702 var ix = this.view.indexOf(csel[0]);
41703 cselitem = this.store.getAt(ix);
41704 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41710 this.store.each(function(v) {
41712 // start at existing selection.
41713 if (cselitem.id == v.id) {
41719 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41720 match = this.store.indexOf(v);
41725 if (match === false) {
41726 return true; // no more action?
41729 this.view.select(match);
41730 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41731 sn.scrollIntoView(sn.dom.parentNode, false);
41735 * @cfg {Boolean} grow
41739 * @cfg {Number} growMin
41743 * @cfg {Number} growMax
41751 * Copyright(c) 2010-2012, Roo J Solutions Limited
41758 * @class Roo.form.ComboBoxArray
41759 * @extends Roo.form.TextField
41760 * A facebook style adder... for lists of email / people / countries etc...
41761 * pick multiple items from a combo box, and shows each one.
41763 * Fred [x] Brian [x] [Pick another |v]
41766 * For this to work: it needs various extra information
41767 * - normal combo problay has
41769 * + displayField, valueField
41771 * For our purpose...
41774 * If we change from 'extends' to wrapping...
41781 * Create a new ComboBoxArray.
41782 * @param {Object} config Configuration options
41786 Roo.form.ComboBoxArray = function(config)
41790 * @event beforeremove
41791 * Fires before remove the value from the list
41792 * @param {Roo.form.ComboBoxArray} _self This combo box array
41793 * @param {Roo.form.ComboBoxArray.Item} item removed item
41795 'beforeremove' : true,
41798 * Fires when remove the value from the list
41799 * @param {Roo.form.ComboBoxArray} _self This combo box array
41800 * @param {Roo.form.ComboBoxArray.Item} item removed item
41807 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41809 this.items = new Roo.util.MixedCollection(false);
41811 // construct the child combo...
41821 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41824 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41829 // behavies liek a hiddne field
41830 inputType: 'hidden',
41832 * @cfg {Number} width The width of the box that displays the selected element
41839 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41843 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41845 hiddenName : false,
41848 // private the array of items that are displayed..
41850 // private - the hidden field el.
41852 // private - the filed el..
41855 //validateValue : function() { return true; }, // all values are ok!
41856 //onAddClick: function() { },
41858 onRender : function(ct, position)
41861 // create the standard hidden element
41862 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
41865 // give fake names to child combo;
41866 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
41867 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
41869 this.combo = Roo.factory(this.combo, Roo.form);
41870 this.combo.onRender(ct, position);
41871 if (typeof(this.combo.width) != 'undefined') {
41872 this.combo.onResize(this.combo.width,0);
41875 this.combo.initEvents();
41877 // assigned so form know we need to do this..
41878 this.store = this.combo.store;
41879 this.valueField = this.combo.valueField;
41880 this.displayField = this.combo.displayField ;
41883 this.combo.wrap.addClass('x-cbarray-grp');
41885 var cbwrap = this.combo.wrap.createChild(
41886 {tag: 'div', cls: 'x-cbarray-cb'},
41891 this.hiddenEl = this.combo.wrap.createChild({
41892 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
41894 this.el = this.combo.wrap.createChild({
41895 tag: 'input', type:'hidden' , name: this.name, value : ''
41897 // this.el.dom.removeAttribute("name");
41900 this.outerWrap = this.combo.wrap;
41901 this.wrap = cbwrap;
41903 this.outerWrap.setWidth(this.width);
41904 this.outerWrap.dom.removeChild(this.el.dom);
41906 this.wrap.dom.appendChild(this.el.dom);
41907 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
41908 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
41910 this.combo.trigger.setStyle('position','relative');
41911 this.combo.trigger.setStyle('left', '0px');
41912 this.combo.trigger.setStyle('top', '2px');
41914 this.combo.el.setStyle('vertical-align', 'text-bottom');
41916 //this.trigger.setStyle('vertical-align', 'top');
41918 // this should use the code from combo really... on('add' ....)
41922 this.adder = this.outerWrap.createChild(
41923 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
41925 this.adder.on('click', function(e) {
41926 _t.fireEvent('adderclick', this, e);
41930 //this.adder.on('click', this.onAddClick, _t);
41933 this.combo.on('select', function(cb, rec, ix) {
41934 this.addItem(rec.data);
41937 cb.el.dom.value = '';
41938 //cb.lastData = rec.data;
41947 getName: function()
41949 // returns hidden if it's set..
41950 if (!this.rendered) {return ''};
41951 return this.hiddenName ? this.hiddenName : this.name;
41956 onResize: function(w, h){
41959 // not sure if this is needed..
41960 //this.combo.onResize(w,h);
41962 if(typeof w != 'number'){
41963 // we do not handle it!?!?
41966 var tw = this.combo.trigger.getWidth();
41967 tw += this.addicon ? this.addicon.getWidth() : 0;
41968 tw += this.editicon ? this.editicon.getWidth() : 0;
41970 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
41972 this.combo.trigger.setStyle('left', '0px');
41974 if(this.list && this.listWidth === undefined){
41975 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
41976 this.list.setWidth(lw);
41977 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41984 addItem: function(rec)
41986 var valueField = this.combo.valueField;
41987 var displayField = this.combo.displayField;
41988 if (this.items.indexOfKey(rec[valueField]) > -1) {
41989 //console.log("GOT " + rec.data.id);
41993 var x = new Roo.form.ComboBoxArray.Item({
41994 //id : rec[this.idField],
41996 displayField : displayField ,
41997 tipField : displayField ,
42001 this.items.add(rec[valueField],x);
42002 // add it before the element..
42003 this.updateHiddenEl();
42004 x.render(this.outerWrap, this.wrap.dom);
42005 // add the image handler..
42008 updateHiddenEl : function()
42011 if (!this.hiddenEl) {
42015 var idField = this.combo.valueField;
42017 this.items.each(function(f) {
42018 ar.push(f.data[idField]);
42021 this.hiddenEl.dom.value = ar.join(',');
42027 this.items.clear();
42029 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42033 this.el.dom.value = '';
42034 if (this.hiddenEl) {
42035 this.hiddenEl.dom.value = '';
42039 getValue: function()
42041 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42043 setValue: function(v) // not a valid action - must use addItems..
42050 if (this.store.isLocal && (typeof(v) == 'string')) {
42051 // then we can use the store to find the values..
42052 // comma seperated at present.. this needs to allow JSON based encoding..
42053 this.hiddenEl.value = v;
42055 Roo.each(v.split(','), function(k) {
42056 Roo.log("CHECK " + this.valueField + ',' + k);
42057 var li = this.store.query(this.valueField, k);
42062 add[this.valueField] = k;
42063 add[this.displayField] = li.item(0).data[this.displayField];
42069 if (typeof(v) == 'object' ) {
42070 // then let's assume it's an array of objects..
42071 Roo.each(v, function(l) {
42079 setFromData: function(v)
42081 // this recieves an object, if setValues is called.
42083 this.el.dom.value = v[this.displayField];
42084 this.hiddenEl.dom.value = v[this.valueField];
42085 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42088 var kv = v[this.valueField];
42089 var dv = v[this.displayField];
42090 kv = typeof(kv) != 'string' ? '' : kv;
42091 dv = typeof(dv) != 'string' ? '' : dv;
42094 var keys = kv.split(',');
42095 var display = dv.split(',');
42096 for (var i = 0 ; i < keys.length; i++) {
42099 add[this.valueField] = keys[i];
42100 add[this.displayField] = display[i];
42108 * Validates the combox array value
42109 * @return {Boolean} True if the value is valid, else false
42111 validate : function(){
42112 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42113 this.clearInvalid();
42119 validateValue : function(value){
42120 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42128 isDirty : function() {
42129 if(this.disabled) {
42134 var d = Roo.decode(String(this.originalValue));
42136 return String(this.getValue()) !== String(this.originalValue);
42139 var originalValue = [];
42141 for (var i = 0; i < d.length; i++){
42142 originalValue.push(d[i][this.valueField]);
42145 return String(this.getValue()) !== String(originalValue.join(','));
42154 * @class Roo.form.ComboBoxArray.Item
42155 * @extends Roo.BoxComponent
42156 * A selected item in the list
42157 * Fred [x] Brian [x] [Pick another |v]
42160 * Create a new item.
42161 * @param {Object} config Configuration options
42164 Roo.form.ComboBoxArray.Item = function(config) {
42165 config.id = Roo.id();
42166 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42169 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42172 displayField : false,
42176 defaultAutoCreate : {
42178 cls: 'x-cbarray-item',
42185 src : Roo.BLANK_IMAGE_URL ,
42193 onRender : function(ct, position)
42195 Roo.form.Field.superclass.onRender.call(this, ct, position);
42198 var cfg = this.getAutoCreate();
42199 this.el = ct.createChild(cfg, position);
42202 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42204 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42205 this.cb.renderer(this.data) :
42206 String.format('{0}',this.data[this.displayField]);
42209 this.el.child('div').dom.setAttribute('qtip',
42210 String.format('{0}',this.data[this.tipField])
42213 this.el.child('img').on('click', this.remove, this);
42217 remove : function()
42219 if(this.cb.disabled){
42223 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42224 this.cb.items.remove(this);
42225 this.el.child('img').un('click', this.remove, this);
42227 this.cb.updateHiddenEl();
42229 this.cb.fireEvent('remove', this.cb, this);
42235 * Ext JS Library 1.1.1
42236 * Copyright(c) 2006-2007, Ext JS, LLC.
42238 * Originally Released Under LGPL - original licence link has changed is not relivant.
42241 * <script type="text/javascript">
42244 * @class Roo.form.Checkbox
42245 * @extends Roo.form.Field
42246 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42248 * Creates a new Checkbox
42249 * @param {Object} config Configuration options
42251 Roo.form.Checkbox = function(config){
42252 Roo.form.Checkbox.superclass.constructor.call(this, config);
42256 * Fires when the checkbox is checked or unchecked.
42257 * @param {Roo.form.Checkbox} this This checkbox
42258 * @param {Boolean} checked The new checked value
42264 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42266 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42268 focusClass : undefined,
42270 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42272 fieldClass: "x-form-field",
42274 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42278 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42279 * {tag: "input", type: "checkbox", autocomplete: "off"})
42281 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42283 * @cfg {String} boxLabel The text that appears beside the checkbox
42287 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42291 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42293 valueOff: '0', // value when not checked..
42295 actionMode : 'viewEl',
42298 itemCls : 'x-menu-check-item x-form-item',
42299 groupClass : 'x-menu-group-item',
42300 inputType : 'hidden',
42303 inSetChecked: false, // check that we are not calling self...
42305 inputElement: false, // real input element?
42306 basedOn: false, // ????
42308 isFormField: true, // not sure where this is needed!!!!
42310 onResize : function(){
42311 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42312 if(!this.boxLabel){
42313 this.el.alignTo(this.wrap, 'c-c');
42317 initEvents : function(){
42318 Roo.form.Checkbox.superclass.initEvents.call(this);
42319 this.el.on("click", this.onClick, this);
42320 this.el.on("change", this.onClick, this);
42324 getResizeEl : function(){
42328 getPositionEl : function(){
42333 onRender : function(ct, position){
42334 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42336 if(this.inputValue !== undefined){
42337 this.el.dom.value = this.inputValue;
42340 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42341 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42342 var viewEl = this.wrap.createChild({
42343 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42344 this.viewEl = viewEl;
42345 this.wrap.on('click', this.onClick, this);
42347 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42348 this.el.on('propertychange', this.setFromHidden, this); //ie
42353 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42354 // viewEl.on('click', this.onClick, this);
42356 //if(this.checked){
42357 this.setChecked(this.checked);
42359 //this.checked = this.el.dom;
42365 initValue : Roo.emptyFn,
42368 * Returns the checked state of the checkbox.
42369 * @return {Boolean} True if checked, else false
42371 getValue : function(){
42373 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42375 return this.valueOff;
42380 onClick : function(){
42381 if (this.disabled) {
42384 this.setChecked(!this.checked);
42386 //if(this.el.dom.checked != this.checked){
42387 // this.setValue(this.el.dom.checked);
42392 * Sets the checked state of the checkbox.
42393 * On is always based on a string comparison between inputValue and the param.
42394 * @param {Boolean/String} value - the value to set
42395 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42397 setValue : function(v,suppressEvent){
42400 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42401 //if(this.el && this.el.dom){
42402 // this.el.dom.checked = this.checked;
42403 // this.el.dom.defaultChecked = this.checked;
42405 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42406 //this.fireEvent("check", this, this.checked);
42409 setChecked : function(state,suppressEvent)
42411 if (this.inSetChecked) {
42412 this.checked = state;
42418 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42420 this.checked = state;
42421 if(suppressEvent !== true){
42422 this.fireEvent('check', this, state);
42424 this.inSetChecked = true;
42425 this.el.dom.value = state ? this.inputValue : this.valueOff;
42426 this.inSetChecked = false;
42429 // handle setting of hidden value by some other method!!?!?
42430 setFromHidden: function()
42435 //console.log("SET FROM HIDDEN");
42436 //alert('setFrom hidden');
42437 this.setValue(this.el.dom.value);
42440 onDestroy : function()
42443 Roo.get(this.viewEl).remove();
42446 Roo.form.Checkbox.superclass.onDestroy.call(this);
42449 setBoxLabel : function(str)
42451 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42456 * Ext JS Library 1.1.1
42457 * Copyright(c) 2006-2007, Ext JS, LLC.
42459 * Originally Released Under LGPL - original licence link has changed is not relivant.
42462 * <script type="text/javascript">
42466 * @class Roo.form.Radio
42467 * @extends Roo.form.Checkbox
42468 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42469 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42471 * Creates a new Radio
42472 * @param {Object} config Configuration options
42474 Roo.form.Radio = function(){
42475 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42477 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42478 inputType: 'radio',
42481 * If this radio is part of a group, it will return the selected value
42484 getGroupValue : function(){
42485 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42489 onRender : function(ct, position){
42490 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42492 if(this.inputValue !== undefined){
42493 this.el.dom.value = this.inputValue;
42496 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42497 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42498 //var viewEl = this.wrap.createChild({
42499 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42500 //this.viewEl = viewEl;
42501 //this.wrap.on('click', this.onClick, this);
42503 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42504 //this.el.on('propertychange', this.setFromHidden, this); //ie
42509 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42510 // viewEl.on('click', this.onClick, this);
42513 this.el.dom.checked = 'checked' ;
42519 });//<script type="text/javascript">
42522 * Based Ext JS Library 1.1.1
42523 * Copyright(c) 2006-2007, Ext JS, LLC.
42529 * @class Roo.HtmlEditorCore
42530 * @extends Roo.Component
42531 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42533 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42536 Roo.HtmlEditorCore = function(config){
42539 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42544 * @event initialize
42545 * Fires when the editor is fully initialized (including the iframe)
42546 * @param {Roo.HtmlEditorCore} this
42551 * Fires when the editor is first receives the focus. Any insertion must wait
42552 * until after this event.
42553 * @param {Roo.HtmlEditorCore} this
42557 * @event beforesync
42558 * Fires before the textarea is updated with content from the editor iframe. Return false
42559 * to cancel the sync.
42560 * @param {Roo.HtmlEditorCore} this
42561 * @param {String} html
42565 * @event beforepush
42566 * Fires before the iframe editor is updated with content from the textarea. Return false
42567 * to cancel the push.
42568 * @param {Roo.HtmlEditorCore} this
42569 * @param {String} html
42574 * Fires when the textarea is updated with content from the editor iframe.
42575 * @param {Roo.HtmlEditorCore} this
42576 * @param {String} html
42581 * Fires when the iframe editor is updated with content from the textarea.
42582 * @param {Roo.HtmlEditorCore} this
42583 * @param {String} html
42588 * @event editorevent
42589 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42590 * @param {Roo.HtmlEditorCore} this
42596 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42598 // defaults : white / black...
42599 this.applyBlacklists();
42606 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42610 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42616 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42621 * @cfg {Number} height (in pixels)
42625 * @cfg {Number} width (in pixels)
42630 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42633 stylesheets: false,
42638 // private properties
42639 validationEvent : false,
42641 initialized : false,
42643 sourceEditMode : false,
42644 onFocus : Roo.emptyFn,
42646 hideMode:'offsets',
42650 // blacklist + whitelisted elements..
42657 * Protected method that will not generally be called directly. It
42658 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42659 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42661 getDocMarkup : function(){
42665 // inherit styels from page...??
42666 if (this.stylesheets === false) {
42668 Roo.get(document.head).select('style').each(function(node) {
42669 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42672 Roo.get(document.head).select('link').each(function(node) {
42673 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42676 } else if (!this.stylesheets.length) {
42678 st = '<style type="text/css">' +
42679 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42685 st += '<style type="text/css">' +
42686 'IMG { cursor: pointer } ' +
42690 return '<html><head>' + st +
42691 //<style type="text/css">' +
42692 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42694 ' </head><body class="roo-htmleditor-body"></body></html>';
42698 onRender : function(ct, position)
42701 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42702 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42705 this.el.dom.style.border = '0 none';
42706 this.el.dom.setAttribute('tabIndex', -1);
42707 this.el.addClass('x-hidden hide');
42711 if(Roo.isIE){ // fix IE 1px bogus margin
42712 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42716 this.frameId = Roo.id();
42720 var iframe = this.owner.wrap.createChild({
42722 cls: 'form-control', // bootstrap..
42724 name: this.frameId,
42725 frameBorder : 'no',
42726 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42731 this.iframe = iframe.dom;
42733 this.assignDocWin();
42735 this.doc.designMode = 'on';
42738 this.doc.write(this.getDocMarkup());
42742 var task = { // must defer to wait for browser to be ready
42744 //console.log("run task?" + this.doc.readyState);
42745 this.assignDocWin();
42746 if(this.doc.body || this.doc.readyState == 'complete'){
42748 this.doc.designMode="on";
42752 Roo.TaskMgr.stop(task);
42753 this.initEditor.defer(10, this);
42760 Roo.TaskMgr.start(task);
42765 onResize : function(w, h)
42767 Roo.log('resize: ' +w + ',' + h );
42768 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42772 if(typeof w == 'number'){
42774 this.iframe.style.width = w + 'px';
42776 if(typeof h == 'number'){
42778 this.iframe.style.height = h + 'px';
42780 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42787 * Toggles the editor between standard and source edit mode.
42788 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42790 toggleSourceEdit : function(sourceEditMode){
42792 this.sourceEditMode = sourceEditMode === true;
42794 if(this.sourceEditMode){
42796 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42799 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42800 //this.iframe.className = '';
42803 //this.setSize(this.owner.wrap.getSize());
42804 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42811 * Protected method that will not generally be called directly. If you need/want
42812 * custom HTML cleanup, this is the method you should override.
42813 * @param {String} html The HTML to be cleaned
42814 * return {String} The cleaned HTML
42816 cleanHtml : function(html){
42817 html = String(html);
42818 if(html.length > 5){
42819 if(Roo.isSafari){ // strip safari nonsense
42820 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42823 if(html == ' '){
42830 * HTML Editor -> Textarea
42831 * Protected method that will not generally be called directly. Syncs the contents
42832 * of the editor iframe with the textarea.
42834 syncValue : function(){
42835 if(this.initialized){
42836 var bd = (this.doc.body || this.doc.documentElement);
42837 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42838 var html = bd.innerHTML;
42840 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42841 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42843 html = '<div style="'+m[0]+'">' + html + '</div>';
42846 html = this.cleanHtml(html);
42847 // fix up the special chars.. normaly like back quotes in word...
42848 // however we do not want to do this with chinese..
42849 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42850 var cc = b.charCodeAt();
42852 (cc >= 0x4E00 && cc < 0xA000 ) ||
42853 (cc >= 0x3400 && cc < 0x4E00 ) ||
42854 (cc >= 0xf900 && cc < 0xfb00 )
42860 if(this.owner.fireEvent('beforesync', this, html) !== false){
42861 this.el.dom.value = html;
42862 this.owner.fireEvent('sync', this, html);
42868 * Protected method that will not generally be called directly. Pushes the value of the textarea
42869 * into the iframe editor.
42871 pushValue : function(){
42872 if(this.initialized){
42873 var v = this.el.dom.value.trim();
42875 // if(v.length < 1){
42879 if(this.owner.fireEvent('beforepush', this, v) !== false){
42880 var d = (this.doc.body || this.doc.documentElement);
42882 this.cleanUpPaste();
42883 this.el.dom.value = d.innerHTML;
42884 this.owner.fireEvent('push', this, v);
42890 deferFocus : function(){
42891 this.focus.defer(10, this);
42895 focus : function(){
42896 if(this.win && !this.sourceEditMode){
42903 assignDocWin: function()
42905 var iframe = this.iframe;
42908 this.doc = iframe.contentWindow.document;
42909 this.win = iframe.contentWindow;
42911 // if (!Roo.get(this.frameId)) {
42914 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
42915 // this.win = Roo.get(this.frameId).dom.contentWindow;
42917 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
42921 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
42922 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
42927 initEditor : function(){
42928 //console.log("INIT EDITOR");
42929 this.assignDocWin();
42933 this.doc.designMode="on";
42935 this.doc.write(this.getDocMarkup());
42938 var dbody = (this.doc.body || this.doc.documentElement);
42939 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
42940 // this copies styles from the containing element into thsi one..
42941 // not sure why we need all of this..
42942 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
42944 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
42945 //ss['background-attachment'] = 'fixed'; // w3c
42946 dbody.bgProperties = 'fixed'; // ie
42947 //Roo.DomHelper.applyStyles(dbody, ss);
42948 Roo.EventManager.on(this.doc, {
42949 //'mousedown': this.onEditorEvent,
42950 'mouseup': this.onEditorEvent,
42951 'dblclick': this.onEditorEvent,
42952 'click': this.onEditorEvent,
42953 'keyup': this.onEditorEvent,
42958 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
42960 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
42961 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
42963 this.initialized = true;
42965 this.owner.fireEvent('initialize', this);
42970 onDestroy : function(){
42976 //for (var i =0; i < this.toolbars.length;i++) {
42977 // // fixme - ask toolbars for heights?
42978 // this.toolbars[i].onDestroy();
42981 //this.wrap.dom.innerHTML = '';
42982 //this.wrap.remove();
42987 onFirstFocus : function(){
42989 this.assignDocWin();
42992 this.activated = true;
42995 if(Roo.isGecko){ // prevent silly gecko errors
42997 var s = this.win.getSelection();
42998 if(!s.focusNode || s.focusNode.nodeType != 3){
42999 var r = s.getRangeAt(0);
43000 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43005 this.execCmd('useCSS', true);
43006 this.execCmd('styleWithCSS', false);
43009 this.owner.fireEvent('activate', this);
43013 adjustFont: function(btn){
43014 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43015 //if(Roo.isSafari){ // safari
43018 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43019 if(Roo.isSafari){ // safari
43020 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43021 v = (v < 10) ? 10 : v;
43022 v = (v > 48) ? 48 : v;
43023 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43028 v = Math.max(1, v+adjust);
43030 this.execCmd('FontSize', v );
43033 onEditorEvent : function(e)
43035 this.owner.fireEvent('editorevent', this, e);
43036 // this.updateToolbar();
43037 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43040 insertTag : function(tg)
43042 // could be a bit smarter... -> wrap the current selected tRoo..
43043 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43045 range = this.createRange(this.getSelection());
43046 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43047 wrappingNode.appendChild(range.extractContents());
43048 range.insertNode(wrappingNode);
43055 this.execCmd("formatblock", tg);
43059 insertText : function(txt)
43063 var range = this.createRange();
43064 range.deleteContents();
43065 //alert(Sender.getAttribute('label'));
43067 range.insertNode(this.doc.createTextNode(txt));
43073 * Executes a Midas editor command on the editor document and performs necessary focus and
43074 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43075 * @param {String} cmd The Midas command
43076 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43078 relayCmd : function(cmd, value){
43080 this.execCmd(cmd, value);
43081 this.owner.fireEvent('editorevent', this);
43082 //this.updateToolbar();
43083 this.owner.deferFocus();
43087 * Executes a Midas editor command directly on the editor document.
43088 * For visual commands, you should use {@link #relayCmd} instead.
43089 * <b>This should only be called after the editor is initialized.</b>
43090 * @param {String} cmd The Midas command
43091 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43093 execCmd : function(cmd, value){
43094 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43101 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43103 * @param {String} text | dom node..
43105 insertAtCursor : function(text)
43110 if(!this.activated){
43116 var r = this.doc.selection.createRange();
43127 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43131 // from jquery ui (MIT licenced)
43133 var win = this.win;
43135 if (win.getSelection && win.getSelection().getRangeAt) {
43136 range = win.getSelection().getRangeAt(0);
43137 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43138 range.insertNode(node);
43139 } else if (win.document.selection && win.document.selection.createRange) {
43140 // no firefox support
43141 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43142 win.document.selection.createRange().pasteHTML(txt);
43144 // no firefox support
43145 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43146 this.execCmd('InsertHTML', txt);
43155 mozKeyPress : function(e){
43157 var c = e.getCharCode(), cmd;
43160 c = String.fromCharCode(c).toLowerCase();
43174 this.cleanUpPaste.defer(100, this);
43182 e.preventDefault();
43190 fixKeys : function(){ // load time branching for fastest keydown performance
43192 return function(e){
43193 var k = e.getKey(), r;
43196 r = this.doc.selection.createRange();
43199 r.pasteHTML('    ');
43206 r = this.doc.selection.createRange();
43208 var target = r.parentElement();
43209 if(!target || target.tagName.toLowerCase() != 'li'){
43211 r.pasteHTML('<br />');
43217 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43218 this.cleanUpPaste.defer(100, this);
43224 }else if(Roo.isOpera){
43225 return function(e){
43226 var k = e.getKey();
43230 this.execCmd('InsertHTML','    ');
43233 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43234 this.cleanUpPaste.defer(100, this);
43239 }else if(Roo.isSafari){
43240 return function(e){
43241 var k = e.getKey();
43245 this.execCmd('InsertText','\t');
43249 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43250 this.cleanUpPaste.defer(100, this);
43258 getAllAncestors: function()
43260 var p = this.getSelectedNode();
43263 a.push(p); // push blank onto stack..
43264 p = this.getParentElement();
43268 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43272 a.push(this.doc.body);
43276 lastSelNode : false,
43279 getSelection : function()
43281 this.assignDocWin();
43282 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43285 getSelectedNode: function()
43287 // this may only work on Gecko!!!
43289 // should we cache this!!!!
43294 var range = this.createRange(this.getSelection()).cloneRange();
43297 var parent = range.parentElement();
43299 var testRange = range.duplicate();
43300 testRange.moveToElementText(parent);
43301 if (testRange.inRange(range)) {
43304 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43307 parent = parent.parentElement;
43312 // is ancestor a text element.
43313 var ac = range.commonAncestorContainer;
43314 if (ac.nodeType == 3) {
43315 ac = ac.parentNode;
43318 var ar = ac.childNodes;
43321 var other_nodes = [];
43322 var has_other_nodes = false;
43323 for (var i=0;i<ar.length;i++) {
43324 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43327 // fullly contained node.
43329 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43334 // probably selected..
43335 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43336 other_nodes.push(ar[i]);
43340 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43345 has_other_nodes = true;
43347 if (!nodes.length && other_nodes.length) {
43348 nodes= other_nodes;
43350 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43356 createRange: function(sel)
43358 // this has strange effects when using with
43359 // top toolbar - not sure if it's a great idea.
43360 //this.editor.contentWindow.focus();
43361 if (typeof sel != "undefined") {
43363 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43365 return this.doc.createRange();
43368 return this.doc.createRange();
43371 getParentElement: function()
43374 this.assignDocWin();
43375 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43377 var range = this.createRange(sel);
43380 var p = range.commonAncestorContainer;
43381 while (p.nodeType == 3) { // text node
43392 * Range intersection.. the hard stuff...
43396 * [ -- selected range --- ]
43400 * if end is before start or hits it. fail.
43401 * if start is after end or hits it fail.
43403 * if either hits (but other is outside. - then it's not
43409 // @see http://www.thismuchiknow.co.uk/?p=64.
43410 rangeIntersectsNode : function(range, node)
43412 var nodeRange = node.ownerDocument.createRange();
43414 nodeRange.selectNode(node);
43416 nodeRange.selectNodeContents(node);
43419 var rangeStartRange = range.cloneRange();
43420 rangeStartRange.collapse(true);
43422 var rangeEndRange = range.cloneRange();
43423 rangeEndRange.collapse(false);
43425 var nodeStartRange = nodeRange.cloneRange();
43426 nodeStartRange.collapse(true);
43428 var nodeEndRange = nodeRange.cloneRange();
43429 nodeEndRange.collapse(false);
43431 return rangeStartRange.compareBoundaryPoints(
43432 Range.START_TO_START, nodeEndRange) == -1 &&
43433 rangeEndRange.compareBoundaryPoints(
43434 Range.START_TO_START, nodeStartRange) == 1;
43438 rangeCompareNode : function(range, node)
43440 var nodeRange = node.ownerDocument.createRange();
43442 nodeRange.selectNode(node);
43444 nodeRange.selectNodeContents(node);
43448 range.collapse(true);
43450 nodeRange.collapse(true);
43452 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43453 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43455 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43457 var nodeIsBefore = ss == 1;
43458 var nodeIsAfter = ee == -1;
43460 if (nodeIsBefore && nodeIsAfter) {
43463 if (!nodeIsBefore && nodeIsAfter) {
43464 return 1; //right trailed.
43467 if (nodeIsBefore && !nodeIsAfter) {
43468 return 2; // left trailed.
43474 // private? - in a new class?
43475 cleanUpPaste : function()
43477 // cleans up the whole document..
43478 Roo.log('cleanuppaste');
43480 this.cleanUpChildren(this.doc.body);
43481 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43482 if (clean != this.doc.body.innerHTML) {
43483 this.doc.body.innerHTML = clean;
43488 cleanWordChars : function(input) {// change the chars to hex code
43489 var he = Roo.HtmlEditorCore;
43491 var output = input;
43492 Roo.each(he.swapCodes, function(sw) {
43493 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43495 output = output.replace(swapper, sw[1]);
43502 cleanUpChildren : function (n)
43504 if (!n.childNodes.length) {
43507 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43508 this.cleanUpChild(n.childNodes[i]);
43515 cleanUpChild : function (node)
43518 //console.log(node);
43519 if (node.nodeName == "#text") {
43520 // clean up silly Windows -- stuff?
43523 if (node.nodeName == "#comment") {
43524 node.parentNode.removeChild(node);
43525 // clean up silly Windows -- stuff?
43528 var lcname = node.tagName.toLowerCase();
43529 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43530 // whitelist of tags..
43532 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43534 node.parentNode.removeChild(node);
43539 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43541 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43542 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43544 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43545 // remove_keep_children = true;
43548 if (remove_keep_children) {
43549 this.cleanUpChildren(node);
43550 // inserts everything just before this node...
43551 while (node.childNodes.length) {
43552 var cn = node.childNodes[0];
43553 node.removeChild(cn);
43554 node.parentNode.insertBefore(cn, node);
43556 node.parentNode.removeChild(node);
43560 if (!node.attributes || !node.attributes.length) {
43561 this.cleanUpChildren(node);
43565 function cleanAttr(n,v)
43568 if (v.match(/^\./) || v.match(/^\//)) {
43571 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43574 if (v.match(/^#/)) {
43577 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43578 node.removeAttribute(n);
43582 var cwhite = this.cwhite;
43583 var cblack = this.cblack;
43585 function cleanStyle(n,v)
43587 if (v.match(/expression/)) { //XSS?? should we even bother..
43588 node.removeAttribute(n);
43592 var parts = v.split(/;/);
43595 Roo.each(parts, function(p) {
43596 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43600 var l = p.split(':').shift().replace(/\s+/g,'');
43601 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43603 if ( cwhite.length && cblack.indexOf(l) > -1) {
43604 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43605 //node.removeAttribute(n);
43609 // only allow 'c whitelisted system attributes'
43610 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43611 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43612 //node.removeAttribute(n);
43622 if (clean.length) {
43623 node.setAttribute(n, clean.join(';'));
43625 node.removeAttribute(n);
43631 for (var i = node.attributes.length-1; i > -1 ; i--) {
43632 var a = node.attributes[i];
43635 if (a.name.toLowerCase().substr(0,2)=='on') {
43636 node.removeAttribute(a.name);
43639 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43640 node.removeAttribute(a.name);
43643 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43644 cleanAttr(a.name,a.value); // fixme..
43647 if (a.name == 'style') {
43648 cleanStyle(a.name,a.value);
43651 /// clean up MS crap..
43652 // tecnically this should be a list of valid class'es..
43655 if (a.name == 'class') {
43656 if (a.value.match(/^Mso/)) {
43657 node.className = '';
43660 if (a.value.match(/body/)) {
43661 node.className = '';
43672 this.cleanUpChildren(node);
43678 * Clean up MS wordisms...
43680 cleanWord : function(node)
43685 this.cleanWord(this.doc.body);
43688 if (node.nodeName == "#text") {
43689 // clean up silly Windows -- stuff?
43692 if (node.nodeName == "#comment") {
43693 node.parentNode.removeChild(node);
43694 // clean up silly Windows -- stuff?
43698 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43699 node.parentNode.removeChild(node);
43703 // remove - but keep children..
43704 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43705 while (node.childNodes.length) {
43706 var cn = node.childNodes[0];
43707 node.removeChild(cn);
43708 node.parentNode.insertBefore(cn, node);
43710 node.parentNode.removeChild(node);
43711 this.iterateChildren(node, this.cleanWord);
43715 if (node.className.length) {
43717 var cn = node.className.split(/\W+/);
43719 Roo.each(cn, function(cls) {
43720 if (cls.match(/Mso[a-zA-Z]+/)) {
43725 node.className = cna.length ? cna.join(' ') : '';
43727 node.removeAttribute("class");
43731 if (node.hasAttribute("lang")) {
43732 node.removeAttribute("lang");
43735 if (node.hasAttribute("style")) {
43737 var styles = node.getAttribute("style").split(";");
43739 Roo.each(styles, function(s) {
43740 if (!s.match(/:/)) {
43743 var kv = s.split(":");
43744 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43747 // what ever is left... we allow.
43750 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43751 if (!nstyle.length) {
43752 node.removeAttribute('style');
43755 this.iterateChildren(node, this.cleanWord);
43761 * iterateChildren of a Node, calling fn each time, using this as the scole..
43762 * @param {DomNode} node node to iterate children of.
43763 * @param {Function} fn method of this class to call on each item.
43765 iterateChildren : function(node, fn)
43767 if (!node.childNodes.length) {
43770 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43771 fn.call(this, node.childNodes[i])
43777 * cleanTableWidths.
43779 * Quite often pasting from word etc.. results in tables with column and widths.
43780 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43783 cleanTableWidths : function(node)
43788 this.cleanTableWidths(this.doc.body);
43793 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43796 Roo.log(node.tagName);
43797 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43798 this.iterateChildren(node, this.cleanTableWidths);
43801 if (node.hasAttribute('width')) {
43802 node.removeAttribute('width');
43806 if (node.hasAttribute("style")) {
43809 var styles = node.getAttribute("style").split(";");
43811 Roo.each(styles, function(s) {
43812 if (!s.match(/:/)) {
43815 var kv = s.split(":");
43816 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43819 // what ever is left... we allow.
43822 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43823 if (!nstyle.length) {
43824 node.removeAttribute('style');
43828 this.iterateChildren(node, this.cleanTableWidths);
43836 domToHTML : function(currentElement, depth, nopadtext) {
43838 depth = depth || 0;
43839 nopadtext = nopadtext || false;
43841 if (!currentElement) {
43842 return this.domToHTML(this.doc.body);
43845 //Roo.log(currentElement);
43847 var allText = false;
43848 var nodeName = currentElement.nodeName;
43849 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43851 if (nodeName == '#text') {
43853 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
43858 if (nodeName != 'BODY') {
43861 // Prints the node tagName, such as <A>, <IMG>, etc
43864 for(i = 0; i < currentElement.attributes.length;i++) {
43866 var aname = currentElement.attributes.item(i).name;
43867 if (!currentElement.attributes.item(i).value.length) {
43870 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
43873 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
43882 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
43885 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
43890 // Traverse the tree
43892 var currentElementChild = currentElement.childNodes.item(i);
43893 var allText = true;
43894 var innerHTML = '';
43896 while (currentElementChild) {
43897 // Formatting code (indent the tree so it looks nice on the screen)
43898 var nopad = nopadtext;
43899 if (lastnode == 'SPAN') {
43903 if (currentElementChild.nodeName == '#text') {
43904 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
43905 toadd = nopadtext ? toadd : toadd.trim();
43906 if (!nopad && toadd.length > 80) {
43907 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
43909 innerHTML += toadd;
43912 currentElementChild = currentElement.childNodes.item(i);
43918 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
43920 // Recursively traverse the tree structure of the child node
43921 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
43922 lastnode = currentElementChild.nodeName;
43924 currentElementChild=currentElement.childNodes.item(i);
43930 // The remaining code is mostly for formatting the tree
43931 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
43936 ret+= "</"+tagName+">";
43942 applyBlacklists : function()
43944 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
43945 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
43949 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
43950 if (b.indexOf(tag) > -1) {
43953 this.white.push(tag);
43957 Roo.each(w, function(tag) {
43958 if (b.indexOf(tag) > -1) {
43961 if (this.white.indexOf(tag) > -1) {
43964 this.white.push(tag);
43969 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
43970 if (w.indexOf(tag) > -1) {
43973 this.black.push(tag);
43977 Roo.each(b, function(tag) {
43978 if (w.indexOf(tag) > -1) {
43981 if (this.black.indexOf(tag) > -1) {
43984 this.black.push(tag);
43989 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
43990 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
43994 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
43995 if (b.indexOf(tag) > -1) {
43998 this.cwhite.push(tag);
44002 Roo.each(w, function(tag) {
44003 if (b.indexOf(tag) > -1) {
44006 if (this.cwhite.indexOf(tag) > -1) {
44009 this.cwhite.push(tag);
44014 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44015 if (w.indexOf(tag) > -1) {
44018 this.cblack.push(tag);
44022 Roo.each(b, function(tag) {
44023 if (w.indexOf(tag) > -1) {
44026 if (this.cblack.indexOf(tag) > -1) {
44029 this.cblack.push(tag);
44034 setStylesheets : function(stylesheets)
44036 if(typeof(stylesheets) == 'string'){
44037 Roo.get(this.iframe.contentDocument.head).createChild({
44039 rel : 'stylesheet',
44048 Roo.each(stylesheets, function(s) {
44053 Roo.get(_this.iframe.contentDocument.head).createChild({
44055 rel : 'stylesheet',
44064 removeStylesheets : function()
44068 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44073 // hide stuff that is not compatible
44087 * @event specialkey
44091 * @cfg {String} fieldClass @hide
44094 * @cfg {String} focusClass @hide
44097 * @cfg {String} autoCreate @hide
44100 * @cfg {String} inputType @hide
44103 * @cfg {String} invalidClass @hide
44106 * @cfg {String} invalidText @hide
44109 * @cfg {String} msgFx @hide
44112 * @cfg {String} validateOnBlur @hide
44116 Roo.HtmlEditorCore.white = [
44117 'area', 'br', 'img', 'input', 'hr', 'wbr',
44119 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44120 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44121 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44122 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44123 'table', 'ul', 'xmp',
44125 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44128 'dir', 'menu', 'ol', 'ul', 'dl',
44134 Roo.HtmlEditorCore.black = [
44135 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44137 'base', 'basefont', 'bgsound', 'blink', 'body',
44138 'frame', 'frameset', 'head', 'html', 'ilayer',
44139 'iframe', 'layer', 'link', 'meta', 'object',
44140 'script', 'style' ,'title', 'xml' // clean later..
44142 Roo.HtmlEditorCore.clean = [
44143 'script', 'style', 'title', 'xml'
44145 Roo.HtmlEditorCore.remove = [
44150 Roo.HtmlEditorCore.ablack = [
44154 Roo.HtmlEditorCore.aclean = [
44155 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44159 Roo.HtmlEditorCore.pwhite= [
44160 'http', 'https', 'mailto'
44163 // white listed style attributes.
44164 Roo.HtmlEditorCore.cwhite= [
44165 // 'text-align', /// default is to allow most things..
44171 // black listed style attributes.
44172 Roo.HtmlEditorCore.cblack= [
44173 // 'font-size' -- this can be set by the project
44177 Roo.HtmlEditorCore.swapCodes =[
44188 //<script type="text/javascript">
44191 * Ext JS Library 1.1.1
44192 * Copyright(c) 2006-2007, Ext JS, LLC.
44198 Roo.form.HtmlEditor = function(config){
44202 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44204 if (!this.toolbars) {
44205 this.toolbars = [];
44207 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44213 * @class Roo.form.HtmlEditor
44214 * @extends Roo.form.Field
44215 * Provides a lightweight HTML Editor component.
44217 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44219 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44220 * supported by this editor.</b><br/><br/>
44221 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44222 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44224 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44226 * @cfg {Boolean} clearUp
44230 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44235 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44240 * @cfg {Number} height (in pixels)
44244 * @cfg {Number} width (in pixels)
44249 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44252 stylesheets: false,
44256 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44261 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44267 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44272 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44280 // private properties
44281 validationEvent : false,
44283 initialized : false,
44286 onFocus : Roo.emptyFn,
44288 hideMode:'offsets',
44290 actionMode : 'container', // defaults to hiding it...
44292 defaultAutoCreate : { // modified by initCompnoent..
44294 style:"width:500px;height:300px;",
44295 autocomplete: "new-password"
44299 initComponent : function(){
44302 * @event initialize
44303 * Fires when the editor is fully initialized (including the iframe)
44304 * @param {HtmlEditor} this
44309 * Fires when the editor is first receives the focus. Any insertion must wait
44310 * until after this event.
44311 * @param {HtmlEditor} this
44315 * @event beforesync
44316 * Fires before the textarea is updated with content from the editor iframe. Return false
44317 * to cancel the sync.
44318 * @param {HtmlEditor} this
44319 * @param {String} html
44323 * @event beforepush
44324 * Fires before the iframe editor is updated with content from the textarea. Return false
44325 * to cancel the push.
44326 * @param {HtmlEditor} this
44327 * @param {String} html
44332 * Fires when the textarea is updated with content from the editor iframe.
44333 * @param {HtmlEditor} this
44334 * @param {String} html
44339 * Fires when the iframe editor is updated with content from the textarea.
44340 * @param {HtmlEditor} this
44341 * @param {String} html
44345 * @event editmodechange
44346 * Fires when the editor switches edit modes
44347 * @param {HtmlEditor} this
44348 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44350 editmodechange: true,
44352 * @event editorevent
44353 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44354 * @param {HtmlEditor} this
44358 * @event firstfocus
44359 * Fires when on first focus - needed by toolbars..
44360 * @param {HtmlEditor} this
44365 * Auto save the htmlEditor value as a file into Events
44366 * @param {HtmlEditor} this
44370 * @event savedpreview
44371 * preview the saved version of htmlEditor
44372 * @param {HtmlEditor} this
44374 savedpreview: true,
44377 * @event stylesheetsclick
44378 * Fires when press the Sytlesheets button
44379 * @param {Roo.HtmlEditorCore} this
44381 stylesheetsclick: true
44383 this.defaultAutoCreate = {
44385 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44386 autocomplete: "new-password"
44391 * Protected method that will not generally be called directly. It
44392 * is called when the editor creates its toolbar. Override this method if you need to
44393 * add custom toolbar buttons.
44394 * @param {HtmlEditor} editor
44396 createToolbar : function(editor){
44397 Roo.log("create toolbars");
44398 if (!editor.toolbars || !editor.toolbars.length) {
44399 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44402 for (var i =0 ; i < editor.toolbars.length;i++) {
44403 editor.toolbars[i] = Roo.factory(
44404 typeof(editor.toolbars[i]) == 'string' ?
44405 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44406 Roo.form.HtmlEditor);
44407 editor.toolbars[i].init(editor);
44415 onRender : function(ct, position)
44418 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44420 this.wrap = this.el.wrap({
44421 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44424 this.editorcore.onRender(ct, position);
44426 if (this.resizable) {
44427 this.resizeEl = new Roo.Resizable(this.wrap, {
44431 minHeight : this.height,
44432 height: this.height,
44433 handles : this.resizable,
44436 resize : function(r, w, h) {
44437 _t.onResize(w,h); // -something
44443 this.createToolbar(this);
44447 this.setSize(this.wrap.getSize());
44449 if (this.resizeEl) {
44450 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44451 // should trigger onReize..
44454 this.keyNav = new Roo.KeyNav(this.el, {
44456 "tab" : function(e){
44457 e.preventDefault();
44459 var value = this.getValue();
44461 var start = this.el.dom.selectionStart;
44462 var end = this.el.dom.selectionEnd;
44466 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44467 this.el.dom.setSelectionRange(end + 1, end + 1);
44471 var f = value.substring(0, start).split("\t");
44473 if(f.pop().length != 0){
44477 this.setValue(f.join("\t") + value.substring(end));
44478 this.el.dom.setSelectionRange(start - 1, start - 1);
44482 "home" : function(e){
44483 e.preventDefault();
44485 var curr = this.el.dom.selectionStart;
44486 var lines = this.getValue().split("\n");
44493 this.el.dom.setSelectionRange(0, 0);
44499 for (var i = 0; i < lines.length;i++) {
44500 pos += lines[i].length;
44510 pos -= lines[i].length;
44516 this.el.dom.setSelectionRange(pos, pos);
44520 this.el.dom.selectionStart = pos;
44521 this.el.dom.selectionEnd = curr;
44524 "end" : function(e){
44525 e.preventDefault();
44527 var curr = this.el.dom.selectionStart;
44528 var lines = this.getValue().split("\n");
44535 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44541 for (var i = 0; i < lines.length;i++) {
44543 pos += lines[i].length;
44557 this.el.dom.setSelectionRange(pos, pos);
44561 this.el.dom.selectionStart = curr;
44562 this.el.dom.selectionEnd = pos;
44567 doRelay : function(foo, bar, hname){
44568 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44574 // if(this.autosave && this.w){
44575 // this.autoSaveFn = setInterval(this.autosave, 1000);
44580 onResize : function(w, h)
44582 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44587 if(typeof w == 'number'){
44588 var aw = w - this.wrap.getFrameWidth('lr');
44589 this.el.setWidth(this.adjustWidth('textarea', aw));
44592 if(typeof h == 'number'){
44594 for (var i =0; i < this.toolbars.length;i++) {
44595 // fixme - ask toolbars for heights?
44596 tbh += this.toolbars[i].tb.el.getHeight();
44597 if (this.toolbars[i].footer) {
44598 tbh += this.toolbars[i].footer.el.getHeight();
44605 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44606 ah -= 5; // knock a few pixes off for look..
44608 this.el.setHeight(this.adjustWidth('textarea', ah));
44612 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44613 this.editorcore.onResize(ew,eh);
44618 * Toggles the editor between standard and source edit mode.
44619 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44621 toggleSourceEdit : function(sourceEditMode)
44623 this.editorcore.toggleSourceEdit(sourceEditMode);
44625 if(this.editorcore.sourceEditMode){
44626 Roo.log('editor - showing textarea');
44629 // Roo.log(this.syncValue());
44630 this.editorcore.syncValue();
44631 this.el.removeClass('x-hidden');
44632 this.el.dom.removeAttribute('tabIndex');
44635 for (var i = 0; i < this.toolbars.length; i++) {
44636 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44637 this.toolbars[i].tb.hide();
44638 this.toolbars[i].footer.hide();
44643 Roo.log('editor - hiding textarea');
44645 // Roo.log(this.pushValue());
44646 this.editorcore.pushValue();
44648 this.el.addClass('x-hidden');
44649 this.el.dom.setAttribute('tabIndex', -1);
44651 for (var i = 0; i < this.toolbars.length; i++) {
44652 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44653 this.toolbars[i].tb.show();
44654 this.toolbars[i].footer.show();
44658 //this.deferFocus();
44661 this.setSize(this.wrap.getSize());
44662 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44664 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44667 // private (for BoxComponent)
44668 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44670 // private (for BoxComponent)
44671 getResizeEl : function(){
44675 // private (for BoxComponent)
44676 getPositionEl : function(){
44681 initEvents : function(){
44682 this.originalValue = this.getValue();
44686 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44689 markInvalid : Roo.emptyFn,
44691 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44694 clearInvalid : Roo.emptyFn,
44696 setValue : function(v){
44697 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44698 this.editorcore.pushValue();
44703 deferFocus : function(){
44704 this.focus.defer(10, this);
44708 focus : function(){
44709 this.editorcore.focus();
44715 onDestroy : function(){
44721 for (var i =0; i < this.toolbars.length;i++) {
44722 // fixme - ask toolbars for heights?
44723 this.toolbars[i].onDestroy();
44726 this.wrap.dom.innerHTML = '';
44727 this.wrap.remove();
44732 onFirstFocus : function(){
44733 //Roo.log("onFirstFocus");
44734 this.editorcore.onFirstFocus();
44735 for (var i =0; i < this.toolbars.length;i++) {
44736 this.toolbars[i].onFirstFocus();
44742 syncValue : function()
44744 this.editorcore.syncValue();
44747 pushValue : function()
44749 this.editorcore.pushValue();
44752 setStylesheets : function(stylesheets)
44754 this.editorcore.setStylesheets(stylesheets);
44757 removeStylesheets : function()
44759 this.editorcore.removeStylesheets();
44763 // hide stuff that is not compatible
44777 * @event specialkey
44781 * @cfg {String} fieldClass @hide
44784 * @cfg {String} focusClass @hide
44787 * @cfg {String} autoCreate @hide
44790 * @cfg {String} inputType @hide
44793 * @cfg {String} invalidClass @hide
44796 * @cfg {String} invalidText @hide
44799 * @cfg {String} msgFx @hide
44802 * @cfg {String} validateOnBlur @hide
44806 // <script type="text/javascript">
44809 * Ext JS Library 1.1.1
44810 * Copyright(c) 2006-2007, Ext JS, LLC.
44816 * @class Roo.form.HtmlEditorToolbar1
44821 new Roo.form.HtmlEditor({
44824 new Roo.form.HtmlEditorToolbar1({
44825 disable : { fonts: 1 , format: 1, ..., ... , ...],
44831 * @cfg {Object} disable List of elements to disable..
44832 * @cfg {Array} btns List of additional buttons.
44836 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44839 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44842 Roo.apply(this, config);
44844 // default disabled, based on 'good practice'..
44845 this.disable = this.disable || {};
44846 Roo.applyIf(this.disable, {
44849 specialElements : true
44853 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44854 // dont call parent... till later.
44857 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
44864 editorcore : false,
44866 * @cfg {Object} disable List of toolbar elements to disable
44873 * @cfg {String} createLinkText The default text for the create link prompt
44875 createLinkText : 'Please enter the URL for the link:',
44877 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
44879 defaultLinkValue : 'http:/'+'/',
44883 * @cfg {Array} fontFamilies An array of available font families
44901 // "á" , ?? a acute?
44906 "°" // , // degrees
44908 // "é" , // e ecute
44909 // "ú" , // u ecute?
44912 specialElements : [
44914 text: "Insert Table",
44917 ihtml : '<table><tr><td>Cell</td></tr></table>'
44921 text: "Insert Image",
44924 ihtml : '<img src="about:blank"/>'
44933 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
44934 "input:submit", "input:button", "select", "textarea", "label" ],
44937 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
44939 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
44947 * @cfg {String} defaultFont default font to use.
44949 defaultFont: 'tahoma',
44951 fontSelect : false,
44954 formatCombo : false,
44956 init : function(editor)
44958 this.editor = editor;
44959 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44960 var editorcore = this.editorcore;
44964 var fid = editorcore.frameId;
44966 function btn(id, toggle, handler){
44967 var xid = fid + '-'+ id ;
44971 cls : 'x-btn-icon x-edit-'+id,
44972 enableToggle:toggle !== false,
44973 scope: _t, // was editor...
44974 handler:handler||_t.relayBtnCmd,
44975 clickEvent:'mousedown',
44976 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44983 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
44985 // stop form submits
44986 tb.el.on('click', function(e){
44987 e.preventDefault(); // what does this do?
44990 if(!this.disable.font) { // && !Roo.isSafari){
44991 /* why no safari for fonts
44992 editor.fontSelect = tb.el.createChild({
44995 cls:'x-font-select',
44996 html: this.createFontOptions()
44999 editor.fontSelect.on('change', function(){
45000 var font = editor.fontSelect.dom.value;
45001 editor.relayCmd('fontname', font);
45002 editor.deferFocus();
45006 editor.fontSelect.dom,
45012 if(!this.disable.formats){
45013 this.formatCombo = new Roo.form.ComboBox({
45014 store: new Roo.data.SimpleStore({
45017 data : this.formats // from states.js
45021 //autoCreate : {tag: "div", size: "20"},
45022 displayField:'tag',
45026 triggerAction: 'all',
45027 emptyText:'Add tag',
45028 selectOnFocus:true,
45031 'select': function(c, r, i) {
45032 editorcore.insertTag(r.get('tag'));
45038 tb.addField(this.formatCombo);
45042 if(!this.disable.format){
45047 btn('strikethrough')
45050 if(!this.disable.fontSize){
45055 btn('increasefontsize', false, editorcore.adjustFont),
45056 btn('decreasefontsize', false, editorcore.adjustFont)
45061 if(!this.disable.colors){
45064 id:editorcore.frameId +'-forecolor',
45065 cls:'x-btn-icon x-edit-forecolor',
45066 clickEvent:'mousedown',
45067 tooltip: this.buttonTips['forecolor'] || undefined,
45069 menu : new Roo.menu.ColorMenu({
45070 allowReselect: true,
45071 focus: Roo.emptyFn,
45074 selectHandler: function(cp, color){
45075 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45076 editor.deferFocus();
45079 clickEvent:'mousedown'
45082 id:editorcore.frameId +'backcolor',
45083 cls:'x-btn-icon x-edit-backcolor',
45084 clickEvent:'mousedown',
45085 tooltip: this.buttonTips['backcolor'] || undefined,
45087 menu : new Roo.menu.ColorMenu({
45088 focus: Roo.emptyFn,
45091 allowReselect: true,
45092 selectHandler: function(cp, color){
45094 editorcore.execCmd('useCSS', false);
45095 editorcore.execCmd('hilitecolor', color);
45096 editorcore.execCmd('useCSS', true);
45097 editor.deferFocus();
45099 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45100 Roo.isSafari || Roo.isIE ? '#'+color : color);
45101 editor.deferFocus();
45105 clickEvent:'mousedown'
45110 // now add all the items...
45113 if(!this.disable.alignments){
45116 btn('justifyleft'),
45117 btn('justifycenter'),
45118 btn('justifyright')
45122 //if(!Roo.isSafari){
45123 if(!this.disable.links){
45126 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45130 if(!this.disable.lists){
45133 btn('insertorderedlist'),
45134 btn('insertunorderedlist')
45137 if(!this.disable.sourceEdit){
45140 btn('sourceedit', true, function(btn){
45141 this.toggleSourceEdit(btn.pressed);
45148 // special menu.. - needs to be tidied up..
45149 if (!this.disable.special) {
45152 cls: 'x-edit-none',
45158 for (var i =0; i < this.specialChars.length; i++) {
45159 smenu.menu.items.push({
45161 html: this.specialChars[i],
45162 handler: function(a,b) {
45163 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45164 //editor.insertAtCursor(a.html);
45178 if (!this.disable.cleanStyles) {
45180 cls: 'x-btn-icon x-btn-clear',
45186 for (var i =0; i < this.cleanStyles.length; i++) {
45187 cmenu.menu.items.push({
45188 actiontype : this.cleanStyles[i],
45189 html: 'Remove ' + this.cleanStyles[i],
45190 handler: function(a,b) {
45193 var c = Roo.get(editorcore.doc.body);
45194 c.select('[style]').each(function(s) {
45195 s.dom.style.removeProperty(a.actiontype);
45197 editorcore.syncValue();
45202 cmenu.menu.items.push({
45203 actiontype : 'tablewidths',
45204 html: 'Remove Table Widths',
45205 handler: function(a,b) {
45206 editorcore.cleanTableWidths();
45207 editorcore.syncValue();
45211 cmenu.menu.items.push({
45212 actiontype : 'word',
45213 html: 'Remove MS Word Formating',
45214 handler: function(a,b) {
45215 editorcore.cleanWord();
45216 editorcore.syncValue();
45221 cmenu.menu.items.push({
45222 actiontype : 'all',
45223 html: 'Remove All Styles',
45224 handler: function(a,b) {
45226 var c = Roo.get(editorcore.doc.body);
45227 c.select('[style]').each(function(s) {
45228 s.dom.removeAttribute('style');
45230 editorcore.syncValue();
45235 cmenu.menu.items.push({
45236 actiontype : 'all',
45237 html: 'Remove All CSS Classes',
45238 handler: function(a,b) {
45240 var c = Roo.get(editorcore.doc.body);
45241 c.select('[class]').each(function(s) {
45242 s.dom.className = '';
45244 editorcore.syncValue();
45249 cmenu.menu.items.push({
45250 actiontype : 'tidy',
45251 html: 'Tidy HTML Source',
45252 handler: function(a,b) {
45253 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45254 editorcore.syncValue();
45263 if (!this.disable.specialElements) {
45266 cls: 'x-edit-none',
45271 for (var i =0; i < this.specialElements.length; i++) {
45272 semenu.menu.items.push(
45274 handler: function(a,b) {
45275 editor.insertAtCursor(this.ihtml);
45277 }, this.specialElements[i])
45289 for(var i =0; i< this.btns.length;i++) {
45290 var b = Roo.factory(this.btns[i],Roo.form);
45291 b.cls = 'x-edit-none';
45293 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45294 b.cls += ' x-init-enable';
45297 b.scope = editorcore;
45305 // disable everything...
45307 this.tb.items.each(function(item){
45310 item.id != editorcore.frameId+ '-sourceedit' &&
45311 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45317 this.rendered = true;
45319 // the all the btns;
45320 editor.on('editorevent', this.updateToolbar, this);
45321 // other toolbars need to implement this..
45322 //editor.on('editmodechange', this.updateToolbar, this);
45326 relayBtnCmd : function(btn) {
45327 this.editorcore.relayCmd(btn.cmd);
45329 // private used internally
45330 createLink : function(){
45331 Roo.log("create link?");
45332 var url = prompt(this.createLinkText, this.defaultLinkValue);
45333 if(url && url != 'http:/'+'/'){
45334 this.editorcore.relayCmd('createlink', url);
45340 * Protected method that will not generally be called directly. It triggers
45341 * a toolbar update by reading the markup state of the current selection in the editor.
45343 updateToolbar: function(){
45345 if(!this.editorcore.activated){
45346 this.editor.onFirstFocus();
45350 var btns = this.tb.items.map,
45351 doc = this.editorcore.doc,
45352 frameId = this.editorcore.frameId;
45354 if(!this.disable.font && !Roo.isSafari){
45356 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45357 if(name != this.fontSelect.dom.value){
45358 this.fontSelect.dom.value = name;
45362 if(!this.disable.format){
45363 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45364 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45365 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45366 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45368 if(!this.disable.alignments){
45369 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45370 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45371 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45373 if(!Roo.isSafari && !this.disable.lists){
45374 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45375 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45378 var ans = this.editorcore.getAllAncestors();
45379 if (this.formatCombo) {
45382 var store = this.formatCombo.store;
45383 this.formatCombo.setValue("");
45384 for (var i =0; i < ans.length;i++) {
45385 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45387 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45395 // hides menus... - so this cant be on a menu...
45396 Roo.menu.MenuMgr.hideAll();
45398 //this.editorsyncValue();
45402 createFontOptions : function(){
45403 var buf = [], fs = this.fontFamilies, ff, lc;
45407 for(var i = 0, len = fs.length; i< len; i++){
45409 lc = ff.toLowerCase();
45411 '<option value="',lc,'" style="font-family:',ff,';"',
45412 (this.defaultFont == lc ? ' selected="true">' : '>'),
45417 return buf.join('');
45420 toggleSourceEdit : function(sourceEditMode){
45422 Roo.log("toolbar toogle");
45423 if(sourceEditMode === undefined){
45424 sourceEditMode = !this.sourceEditMode;
45426 this.sourceEditMode = sourceEditMode === true;
45427 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45428 // just toggle the button?
45429 if(btn.pressed !== this.sourceEditMode){
45430 btn.toggle(this.sourceEditMode);
45434 if(sourceEditMode){
45435 Roo.log("disabling buttons");
45436 this.tb.items.each(function(item){
45437 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45443 Roo.log("enabling buttons");
45444 if(this.editorcore.initialized){
45445 this.tb.items.each(function(item){
45451 Roo.log("calling toggole on editor");
45452 // tell the editor that it's been pressed..
45453 this.editor.toggleSourceEdit(sourceEditMode);
45457 * Object collection of toolbar tooltips for the buttons in the editor. The key
45458 * is the command id associated with that button and the value is a valid QuickTips object.
45463 title: 'Bold (Ctrl+B)',
45464 text: 'Make the selected text bold.',
45465 cls: 'x-html-editor-tip'
45468 title: 'Italic (Ctrl+I)',
45469 text: 'Make the selected text italic.',
45470 cls: 'x-html-editor-tip'
45478 title: 'Bold (Ctrl+B)',
45479 text: 'Make the selected text bold.',
45480 cls: 'x-html-editor-tip'
45483 title: 'Italic (Ctrl+I)',
45484 text: 'Make the selected text italic.',
45485 cls: 'x-html-editor-tip'
45488 title: 'Underline (Ctrl+U)',
45489 text: 'Underline the selected text.',
45490 cls: 'x-html-editor-tip'
45493 title: 'Strikethrough',
45494 text: 'Strikethrough the selected text.',
45495 cls: 'x-html-editor-tip'
45497 increasefontsize : {
45498 title: 'Grow Text',
45499 text: 'Increase the font size.',
45500 cls: 'x-html-editor-tip'
45502 decreasefontsize : {
45503 title: 'Shrink Text',
45504 text: 'Decrease the font size.',
45505 cls: 'x-html-editor-tip'
45508 title: 'Text Highlight Color',
45509 text: 'Change the background color of the selected text.',
45510 cls: 'x-html-editor-tip'
45513 title: 'Font Color',
45514 text: 'Change the color of the selected text.',
45515 cls: 'x-html-editor-tip'
45518 title: 'Align Text Left',
45519 text: 'Align text to the left.',
45520 cls: 'x-html-editor-tip'
45523 title: 'Center Text',
45524 text: 'Center text in the editor.',
45525 cls: 'x-html-editor-tip'
45528 title: 'Align Text Right',
45529 text: 'Align text to the right.',
45530 cls: 'x-html-editor-tip'
45532 insertunorderedlist : {
45533 title: 'Bullet List',
45534 text: 'Start a bulleted list.',
45535 cls: 'x-html-editor-tip'
45537 insertorderedlist : {
45538 title: 'Numbered List',
45539 text: 'Start a numbered list.',
45540 cls: 'x-html-editor-tip'
45543 title: 'Hyperlink',
45544 text: 'Make the selected text a hyperlink.',
45545 cls: 'x-html-editor-tip'
45548 title: 'Source Edit',
45549 text: 'Switch to source editing mode.',
45550 cls: 'x-html-editor-tip'
45554 onDestroy : function(){
45557 this.tb.items.each(function(item){
45559 item.menu.removeAll();
45561 item.menu.el.destroy();
45569 onFirstFocus: function() {
45570 this.tb.items.each(function(item){
45579 // <script type="text/javascript">
45582 * Ext JS Library 1.1.1
45583 * Copyright(c) 2006-2007, Ext JS, LLC.
45590 * @class Roo.form.HtmlEditor.ToolbarContext
45595 new Roo.form.HtmlEditor({
45598 { xtype: 'ToolbarStandard', styles : {} }
45599 { xtype: 'ToolbarContext', disable : {} }
45605 * @config : {Object} disable List of elements to disable.. (not done yet.)
45606 * @config : {Object} styles Map of styles available.
45610 Roo.form.HtmlEditor.ToolbarContext = function(config)
45613 Roo.apply(this, config);
45614 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45615 // dont call parent... till later.
45616 this.styles = this.styles || {};
45621 Roo.form.HtmlEditor.ToolbarContext.types = {
45633 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45699 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45704 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45714 style : 'fontFamily',
45715 displayField: 'display',
45716 optname : 'font-family',
45765 // should we really allow this??
45766 // should this just be
45777 style : 'fontFamily',
45778 displayField: 'display',
45779 optname : 'font-family',
45786 style : 'fontFamily',
45787 displayField: 'display',
45788 optname : 'font-family',
45795 style : 'fontFamily',
45796 displayField: 'display',
45797 optname : 'font-family',
45808 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45809 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45811 Roo.form.HtmlEditor.ToolbarContext.options = {
45813 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45814 [ 'Courier New', 'Courier New'],
45815 [ 'Tahoma', 'Tahoma'],
45816 [ 'Times New Roman,serif', 'Times'],
45817 [ 'Verdana','Verdana' ]
45821 // fixme - these need to be configurable..
45824 //Roo.form.HtmlEditor.ToolbarContext.types
45827 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45834 editorcore : false,
45836 * @cfg {Object} disable List of toolbar elements to disable
45841 * @cfg {Object} styles List of styles
45842 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45844 * These must be defined in the page, so they get rendered correctly..
45855 init : function(editor)
45857 this.editor = editor;
45858 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45859 var editorcore = this.editorcore;
45861 var fid = editorcore.frameId;
45863 function btn(id, toggle, handler){
45864 var xid = fid + '-'+ id ;
45868 cls : 'x-btn-icon x-edit-'+id,
45869 enableToggle:toggle !== false,
45870 scope: editorcore, // was editor...
45871 handler:handler||editorcore.relayBtnCmd,
45872 clickEvent:'mousedown',
45873 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45877 // create a new element.
45878 var wdiv = editor.wrap.createChild({
45880 }, editor.wrap.dom.firstChild.nextSibling, true);
45882 // can we do this more than once??
45884 // stop form submits
45887 // disable everything...
45888 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
45889 this.toolbars = {};
45891 for (var i in ty) {
45893 this.toolbars[i] = this.buildToolbar(ty[i],i);
45895 this.tb = this.toolbars.BODY;
45897 this.buildFooter();
45898 this.footer.show();
45899 editor.on('hide', function( ) { this.footer.hide() }, this);
45900 editor.on('show', function( ) { this.footer.show() }, this);
45903 this.rendered = true;
45905 // the all the btns;
45906 editor.on('editorevent', this.updateToolbar, this);
45907 // other toolbars need to implement this..
45908 //editor.on('editmodechange', this.updateToolbar, this);
45914 * Protected method that will not generally be called directly. It triggers
45915 * a toolbar update by reading the markup state of the current selection in the editor.
45917 * Note you can force an update by calling on('editorevent', scope, false)
45919 updateToolbar: function(editor,ev,sel){
45922 // capture mouse up - this is handy for selecting images..
45923 // perhaps should go somewhere else...
45924 if(!this.editorcore.activated){
45925 this.editor.onFirstFocus();
45931 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
45932 // selectNode - might want to handle IE?
45934 (ev.type == 'mouseup' || ev.type == 'click' ) &&
45935 ev.target && ev.target.tagName == 'IMG') {
45936 // they have click on an image...
45937 // let's see if we can change the selection...
45940 var nodeRange = sel.ownerDocument.createRange();
45942 nodeRange.selectNode(sel);
45944 nodeRange.selectNodeContents(sel);
45946 //nodeRange.collapse(true);
45947 var s = this.editorcore.win.getSelection();
45948 s.removeAllRanges();
45949 s.addRange(nodeRange);
45953 var updateFooter = sel ? false : true;
45956 var ans = this.editorcore.getAllAncestors();
45959 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
45962 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
45963 sel = sel ? sel : this.editorcore.doc.body;
45964 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
45967 // pick a menu that exists..
45968 var tn = sel.tagName.toUpperCase();
45969 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
45971 tn = sel.tagName.toUpperCase();
45973 var lastSel = this.tb.selectedNode;
45975 this.tb.selectedNode = sel;
45977 // if current menu does not match..
45979 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
45982 ///console.log("show: " + tn);
45983 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
45986 this.tb.items.first().el.innerHTML = tn + ': ';
45989 // update attributes
45990 if (this.tb.fields) {
45991 this.tb.fields.each(function(e) {
45993 e.setValue(sel.style[e.stylename]);
45996 e.setValue(sel.getAttribute(e.attrname));
46000 var hasStyles = false;
46001 for(var i in this.styles) {
46008 var st = this.tb.fields.item(0);
46010 st.store.removeAll();
46013 var cn = sel.className.split(/\s+/);
46016 if (this.styles['*']) {
46018 Roo.each(this.styles['*'], function(v) {
46019 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46022 if (this.styles[tn]) {
46023 Roo.each(this.styles[tn], function(v) {
46024 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46028 st.store.loadData(avs);
46032 // flag our selected Node.
46033 this.tb.selectedNode = sel;
46036 Roo.menu.MenuMgr.hideAll();
46040 if (!updateFooter) {
46041 //this.footDisp.dom.innerHTML = '';
46044 // update the footer
46048 this.footerEls = ans.reverse();
46049 Roo.each(this.footerEls, function(a,i) {
46050 if (!a) { return; }
46051 html += html.length ? ' > ' : '';
46053 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46058 var sz = this.footDisp.up('td').getSize();
46059 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46060 this.footDisp.dom.style.marginLeft = '5px';
46062 this.footDisp.dom.style.overflow = 'hidden';
46064 this.footDisp.dom.innerHTML = html;
46066 //this.editorsyncValue();
46073 onDestroy : function(){
46076 this.tb.items.each(function(item){
46078 item.menu.removeAll();
46080 item.menu.el.destroy();
46088 onFirstFocus: function() {
46089 // need to do this for all the toolbars..
46090 this.tb.items.each(function(item){
46094 buildToolbar: function(tlist, nm)
46096 var editor = this.editor;
46097 var editorcore = this.editorcore;
46098 // create a new element.
46099 var wdiv = editor.wrap.createChild({
46101 }, editor.wrap.dom.firstChild.nextSibling, true);
46104 var tb = new Roo.Toolbar(wdiv);
46107 tb.add(nm+ ": ");
46110 for(var i in this.styles) {
46115 if (styles && styles.length) {
46117 // this needs a multi-select checkbox...
46118 tb.addField( new Roo.form.ComboBox({
46119 store: new Roo.data.SimpleStore({
46121 fields: ['val', 'selected'],
46124 name : '-roo-edit-className',
46125 attrname : 'className',
46126 displayField: 'val',
46130 triggerAction: 'all',
46131 emptyText:'Select Style',
46132 selectOnFocus:true,
46135 'select': function(c, r, i) {
46136 // initial support only for on class per el..
46137 tb.selectedNode.className = r ? r.get('val') : '';
46138 editorcore.syncValue();
46145 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46146 var tbops = tbc.options;
46148 for (var i in tlist) {
46150 var item = tlist[i];
46151 tb.add(item.title + ": ");
46154 //optname == used so you can configure the options available..
46155 var opts = item.opts ? item.opts : false;
46156 if (item.optname) {
46157 opts = tbops[item.optname];
46162 // opts == pulldown..
46163 tb.addField( new Roo.form.ComboBox({
46164 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46166 fields: ['val', 'display'],
46169 name : '-roo-edit-' + i,
46171 stylename : item.style ? item.style : false,
46172 displayField: item.displayField ? item.displayField : 'val',
46173 valueField : 'val',
46175 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46177 triggerAction: 'all',
46178 emptyText:'Select',
46179 selectOnFocus:true,
46180 width: item.width ? item.width : 130,
46182 'select': function(c, r, i) {
46184 tb.selectedNode.style[c.stylename] = r.get('val');
46187 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46196 tb.addField( new Roo.form.TextField({
46199 //allowBlank:false,
46204 tb.addField( new Roo.form.TextField({
46205 name: '-roo-edit-' + i,
46212 'change' : function(f, nv, ov) {
46213 tb.selectedNode.setAttribute(f.attrname, nv);
46214 editorcore.syncValue();
46227 text: 'Stylesheets',
46230 click : function ()
46232 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46240 text: 'Remove Tag',
46243 click : function ()
46246 // undo does not work.
46248 var sn = tb.selectedNode;
46250 var pn = sn.parentNode;
46252 var stn = sn.childNodes[0];
46253 var en = sn.childNodes[sn.childNodes.length - 1 ];
46254 while (sn.childNodes.length) {
46255 var node = sn.childNodes[0];
46256 sn.removeChild(node);
46258 pn.insertBefore(node, sn);
46261 pn.removeChild(sn);
46262 var range = editorcore.createRange();
46264 range.setStart(stn,0);
46265 range.setEnd(en,0); //????
46266 //range.selectNode(sel);
46269 var selection = editorcore.getSelection();
46270 selection.removeAllRanges();
46271 selection.addRange(range);
46275 //_this.updateToolbar(null, null, pn);
46276 _this.updateToolbar(null, null, null);
46277 _this.footDisp.dom.innerHTML = '';
46287 tb.el.on('click', function(e){
46288 e.preventDefault(); // what does this do?
46290 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46293 // dont need to disable them... as they will get hidden
46298 buildFooter : function()
46301 var fel = this.editor.wrap.createChild();
46302 this.footer = new Roo.Toolbar(fel);
46303 // toolbar has scrolly on left / right?
46304 var footDisp= new Roo.Toolbar.Fill();
46310 handler : function() {
46311 _t.footDisp.scrollTo('left',0,true)
46315 this.footer.add( footDisp );
46320 handler : function() {
46322 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46326 var fel = Roo.get(footDisp.el);
46327 fel.addClass('x-editor-context');
46328 this.footDispWrap = fel;
46329 this.footDispWrap.overflow = 'hidden';
46331 this.footDisp = fel.createChild();
46332 this.footDispWrap.on('click', this.onContextClick, this)
46336 onContextClick : function (ev,dom)
46338 ev.preventDefault();
46339 var cn = dom.className;
46341 if (!cn.match(/x-ed-loc-/)) {
46344 var n = cn.split('-').pop();
46345 var ans = this.footerEls;
46349 var range = this.editorcore.createRange();
46351 range.selectNodeContents(sel);
46352 //range.selectNode(sel);
46355 var selection = this.editorcore.getSelection();
46356 selection.removeAllRanges();
46357 selection.addRange(range);
46361 this.updateToolbar(null, null, sel);
46378 * Ext JS Library 1.1.1
46379 * Copyright(c) 2006-2007, Ext JS, LLC.
46381 * Originally Released Under LGPL - original licence link has changed is not relivant.
46384 * <script type="text/javascript">
46388 * @class Roo.form.BasicForm
46389 * @extends Roo.util.Observable
46390 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46392 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46393 * @param {Object} config Configuration options
46395 Roo.form.BasicForm = function(el, config){
46396 this.allItems = [];
46397 this.childForms = [];
46398 Roo.apply(this, config);
46400 * The Roo.form.Field items in this form.
46401 * @type MixedCollection
46405 this.items = new Roo.util.MixedCollection(false, function(o){
46406 return o.id || (o.id = Roo.id());
46410 * @event beforeaction
46411 * Fires before any action is performed. Return false to cancel the action.
46412 * @param {Form} this
46413 * @param {Action} action The action to be performed
46415 beforeaction: true,
46417 * @event actionfailed
46418 * Fires when an action fails.
46419 * @param {Form} this
46420 * @param {Action} action The action that failed
46422 actionfailed : true,
46424 * @event actioncomplete
46425 * Fires when an action is completed.
46426 * @param {Form} this
46427 * @param {Action} action The action that completed
46429 actioncomplete : true
46434 Roo.form.BasicForm.superclass.constructor.call(this);
46437 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46439 * @cfg {String} method
46440 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46443 * @cfg {DataReader} reader
46444 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46445 * This is optional as there is built-in support for processing JSON.
46448 * @cfg {DataReader} errorReader
46449 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46450 * This is completely optional as there is built-in support for processing JSON.
46453 * @cfg {String} url
46454 * The URL to use for form actions if one isn't supplied in the action options.
46457 * @cfg {Boolean} fileUpload
46458 * Set to true if this form is a file upload.
46462 * @cfg {Object} baseParams
46463 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46468 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46473 activeAction : null,
46476 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46477 * or setValues() data instead of when the form was first created.
46479 trackResetOnLoad : false,
46483 * childForms - used for multi-tab forms
46486 childForms : false,
46489 * allItems - full list of fields.
46495 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46496 * element by passing it or its id or mask the form itself by passing in true.
46499 waitMsgTarget : false,
46502 initEl : function(el){
46503 this.el = Roo.get(el);
46504 this.id = this.el.id || Roo.id();
46505 this.el.on('submit', this.onSubmit, this);
46506 this.el.addClass('x-form');
46510 onSubmit : function(e){
46515 * Returns true if client-side validation on the form is successful.
46518 isValid : function(){
46520 this.items.each(function(f){
46529 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46532 isDirty : function(){
46534 this.items.each(function(f){
46544 * Returns true if any fields in this form have changed since their original load. (New version)
46548 hasChanged : function()
46551 this.items.each(function(f){
46552 if(f.hasChanged()){
46561 * Resets all hasChanged to 'false' -
46562 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46563 * So hasChanged storage is only to be used for this purpose
46566 resetHasChanged : function()
46568 this.items.each(function(f){
46569 f.resetHasChanged();
46576 * Performs a predefined action (submit or load) or custom actions you define on this form.
46577 * @param {String} actionName The name of the action type
46578 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46579 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46580 * accept other config options):
46582 Property Type Description
46583 ---------------- --------------- ----------------------------------------------------------------------------------
46584 url String The url for the action (defaults to the form's url)
46585 method String The form method to use (defaults to the form's method, or POST if not defined)
46586 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46587 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46588 validate the form on the client (defaults to false)
46590 * @return {BasicForm} this
46592 doAction : function(action, options){
46593 if(typeof action == 'string'){
46594 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46596 if(this.fireEvent('beforeaction', this, action) !== false){
46597 this.beforeAction(action);
46598 action.run.defer(100, action);
46604 * Shortcut to do a submit action.
46605 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46606 * @return {BasicForm} this
46608 submit : function(options){
46609 this.doAction('submit', options);
46614 * Shortcut to do a load action.
46615 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46616 * @return {BasicForm} this
46618 load : function(options){
46619 this.doAction('load', options);
46624 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46625 * @param {Record} record The record to edit
46626 * @return {BasicForm} this
46628 updateRecord : function(record){
46629 record.beginEdit();
46630 var fs = record.fields;
46631 fs.each(function(f){
46632 var field = this.findField(f.name);
46634 record.set(f.name, field.getValue());
46642 * Loads an Roo.data.Record into this form.
46643 * @param {Record} record The record to load
46644 * @return {BasicForm} this
46646 loadRecord : function(record){
46647 this.setValues(record.data);
46652 beforeAction : function(action){
46653 var o = action.options;
46656 if(this.waitMsgTarget === true){
46657 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46658 }else if(this.waitMsgTarget){
46659 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46660 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46662 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46668 afterAction : function(action, success){
46669 this.activeAction = null;
46670 var o = action.options;
46672 if(this.waitMsgTarget === true){
46674 }else if(this.waitMsgTarget){
46675 this.waitMsgTarget.unmask();
46677 Roo.MessageBox.updateProgress(1);
46678 Roo.MessageBox.hide();
46685 Roo.callback(o.success, o.scope, [this, action]);
46686 this.fireEvent('actioncomplete', this, action);
46690 // failure condition..
46691 // we have a scenario where updates need confirming.
46692 // eg. if a locking scenario exists..
46693 // we look for { errors : { needs_confirm : true }} in the response.
46695 (typeof(action.result) != 'undefined') &&
46696 (typeof(action.result.errors) != 'undefined') &&
46697 (typeof(action.result.errors.needs_confirm) != 'undefined')
46700 Roo.MessageBox.confirm(
46701 "Change requires confirmation",
46702 action.result.errorMsg,
46707 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46717 Roo.callback(o.failure, o.scope, [this, action]);
46718 // show an error message if no failed handler is set..
46719 if (!this.hasListener('actionfailed')) {
46720 Roo.MessageBox.alert("Error",
46721 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46722 action.result.errorMsg :
46723 "Saving Failed, please check your entries or try again"
46727 this.fireEvent('actionfailed', this, action);
46733 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46734 * @param {String} id The value to search for
46737 findField : function(id){
46738 var field = this.items.get(id);
46740 this.items.each(function(f){
46741 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46747 return field || null;
46751 * Add a secondary form to this one,
46752 * Used to provide tabbed forms. One form is primary, with hidden values
46753 * which mirror the elements from the other forms.
46755 * @param {Roo.form.Form} form to add.
46758 addForm : function(form)
46761 if (this.childForms.indexOf(form) > -1) {
46765 this.childForms.push(form);
46767 Roo.each(form.allItems, function (fe) {
46769 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46770 if (this.findField(n)) { // already added..
46773 var add = new Roo.form.Hidden({
46776 add.render(this.el);
46783 * Mark fields in this form invalid in bulk.
46784 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46785 * @return {BasicForm} this
46787 markInvalid : function(errors){
46788 if(errors instanceof Array){
46789 for(var i = 0, len = errors.length; i < len; i++){
46790 var fieldError = errors[i];
46791 var f = this.findField(fieldError.id);
46793 f.markInvalid(fieldError.msg);
46799 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46800 field.markInvalid(errors[id]);
46804 Roo.each(this.childForms || [], function (f) {
46805 f.markInvalid(errors);
46812 * Set values for fields in this form in bulk.
46813 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46814 * @return {BasicForm} this
46816 setValues : function(values){
46817 if(values instanceof Array){ // array of objects
46818 for(var i = 0, len = values.length; i < len; i++){
46820 var f = this.findField(v.id);
46822 f.setValue(v.value);
46823 if(this.trackResetOnLoad){
46824 f.originalValue = f.getValue();
46828 }else{ // object hash
46831 if(typeof values[id] != 'function' && (field = this.findField(id))){
46833 if (field.setFromData &&
46834 field.valueField &&
46835 field.displayField &&
46836 // combos' with local stores can
46837 // be queried via setValue()
46838 // to set their value..
46839 (field.store && !field.store.isLocal)
46843 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46844 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46845 field.setFromData(sd);
46848 field.setValue(values[id]);
46852 if(this.trackResetOnLoad){
46853 field.originalValue = field.getValue();
46858 this.resetHasChanged();
46861 Roo.each(this.childForms || [], function (f) {
46862 f.setValues(values);
46863 f.resetHasChanged();
46870 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
46871 * they are returned as an array.
46872 * @param {Boolean} asString
46875 getValues : function(asString){
46876 if (this.childForms) {
46877 // copy values from the child forms
46878 Roo.each(this.childForms, function (f) {
46879 this.setValues(f.getValues());
46885 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
46886 if(asString === true){
46889 return Roo.urlDecode(fs);
46893 * Returns the fields in this form as an object with key/value pairs.
46894 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
46897 getFieldValues : function(with_hidden)
46899 if (this.childForms) {
46900 // copy values from the child forms
46901 // should this call getFieldValues - probably not as we do not currently copy
46902 // hidden fields when we generate..
46903 Roo.each(this.childForms, function (f) {
46904 this.setValues(f.getValues());
46909 this.items.each(function(f){
46910 if (!f.getName()) {
46913 var v = f.getValue();
46914 if (f.inputType =='radio') {
46915 if (typeof(ret[f.getName()]) == 'undefined') {
46916 ret[f.getName()] = ''; // empty..
46919 if (!f.el.dom.checked) {
46923 v = f.el.dom.value;
46927 // not sure if this supported any more..
46928 if ((typeof(v) == 'object') && f.getRawValue) {
46929 v = f.getRawValue() ; // dates..
46931 // combo boxes where name != hiddenName...
46932 if (f.name != f.getName()) {
46933 ret[f.name] = f.getRawValue();
46935 ret[f.getName()] = v;
46942 * Clears all invalid messages in this form.
46943 * @return {BasicForm} this
46945 clearInvalid : function(){
46946 this.items.each(function(f){
46950 Roo.each(this.childForms || [], function (f) {
46959 * Resets this form.
46960 * @return {BasicForm} this
46962 reset : function(){
46963 this.items.each(function(f){
46967 Roo.each(this.childForms || [], function (f) {
46970 this.resetHasChanged();
46976 * Add Roo.form components to this form.
46977 * @param {Field} field1
46978 * @param {Field} field2 (optional)
46979 * @param {Field} etc (optional)
46980 * @return {BasicForm} this
46983 this.items.addAll(Array.prototype.slice.call(arguments, 0));
46989 * Removes a field from the items collection (does NOT remove its markup).
46990 * @param {Field} field
46991 * @return {BasicForm} this
46993 remove : function(field){
46994 this.items.remove(field);
46999 * Looks at the fields in this form, checks them for an id attribute,
47000 * and calls applyTo on the existing dom element with that id.
47001 * @return {BasicForm} this
47003 render : function(){
47004 this.items.each(function(f){
47005 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47013 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47014 * @param {Object} values
47015 * @return {BasicForm} this
47017 applyToFields : function(o){
47018 this.items.each(function(f){
47025 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47026 * @param {Object} values
47027 * @return {BasicForm} this
47029 applyIfToFields : function(o){
47030 this.items.each(function(f){
47038 Roo.BasicForm = Roo.form.BasicForm;/*
47040 * Ext JS Library 1.1.1
47041 * Copyright(c) 2006-2007, Ext JS, LLC.
47043 * Originally Released Under LGPL - original licence link has changed is not relivant.
47046 * <script type="text/javascript">
47050 * @class Roo.form.Form
47051 * @extends Roo.form.BasicForm
47052 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47054 * @param {Object} config Configuration options
47056 Roo.form.Form = function(config){
47058 if (config.items) {
47059 xitems = config.items;
47060 delete config.items;
47064 Roo.form.Form.superclass.constructor.call(this, null, config);
47065 this.url = this.url || this.action;
47067 this.root = new Roo.form.Layout(Roo.applyIf({
47071 this.active = this.root;
47073 * Array of all the buttons that have been added to this form via {@link addButton}
47077 this.allItems = [];
47080 * @event clientvalidation
47081 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47082 * @param {Form} this
47083 * @param {Boolean} valid true if the form has passed client-side validation
47085 clientvalidation: true,
47088 * Fires when the form is rendered
47089 * @param {Roo.form.Form} form
47094 if (this.progressUrl) {
47095 // push a hidden field onto the list of fields..
47099 name : 'UPLOAD_IDENTIFIER'
47104 Roo.each(xitems, this.addxtype, this);
47110 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47112 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47115 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47118 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47120 buttonAlign:'center',
47123 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47128 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47129 * This property cascades to child containers if not set.
47134 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47135 * fires a looping event with that state. This is required to bind buttons to the valid
47136 * state using the config value formBind:true on the button.
47138 monitorValid : false,
47141 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47146 * @cfg {String} progressUrl - Url to return progress data
47149 progressUrl : false,
47152 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47153 * fields are added and the column is closed. If no fields are passed the column remains open
47154 * until end() is called.
47155 * @param {Object} config The config to pass to the column
47156 * @param {Field} field1 (optional)
47157 * @param {Field} field2 (optional)
47158 * @param {Field} etc (optional)
47159 * @return Column The column container object
47161 column : function(c){
47162 var col = new Roo.form.Column(c);
47164 if(arguments.length > 1){ // duplicate code required because of Opera
47165 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47172 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47173 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47174 * until end() is called.
47175 * @param {Object} config The config to pass to the fieldset
47176 * @param {Field} field1 (optional)
47177 * @param {Field} field2 (optional)
47178 * @param {Field} etc (optional)
47179 * @return FieldSet The fieldset container object
47181 fieldset : function(c){
47182 var fs = new Roo.form.FieldSet(c);
47184 if(arguments.length > 1){ // duplicate code required because of Opera
47185 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47192 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47193 * fields are added and the container is closed. If no fields are passed the container remains open
47194 * until end() is called.
47195 * @param {Object} config The config to pass to the Layout
47196 * @param {Field} field1 (optional)
47197 * @param {Field} field2 (optional)
47198 * @param {Field} etc (optional)
47199 * @return Layout The container object
47201 container : function(c){
47202 var l = new Roo.form.Layout(c);
47204 if(arguments.length > 1){ // duplicate code required because of Opera
47205 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47212 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47213 * @param {Object} container A Roo.form.Layout or subclass of Layout
47214 * @return {Form} this
47216 start : function(c){
47217 // cascade label info
47218 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47219 this.active.stack.push(c);
47220 c.ownerCt = this.active;
47226 * Closes the current open container
47227 * @return {Form} this
47230 if(this.active == this.root){
47233 this.active = this.active.ownerCt;
47238 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47239 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47240 * as the label of the field.
47241 * @param {Field} field1
47242 * @param {Field} field2 (optional)
47243 * @param {Field} etc. (optional)
47244 * @return {Form} this
47247 this.active.stack.push.apply(this.active.stack, arguments);
47248 this.allItems.push.apply(this.allItems,arguments);
47250 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47251 if(a[i].isFormField){
47256 Roo.form.Form.superclass.add.apply(this, r);
47266 * Find any element that has been added to a form, using it's ID or name
47267 * This can include framesets, columns etc. along with regular fields..
47268 * @param {String} id - id or name to find.
47270 * @return {Element} e - or false if nothing found.
47272 findbyId : function(id)
47278 Roo.each(this.allItems, function(f){
47279 if (f.id == id || f.name == id ){
47290 * Render this form into the passed container. This should only be called once!
47291 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47292 * @return {Form} this
47294 render : function(ct)
47300 var o = this.autoCreate || {
47302 method : this.method || 'POST',
47303 id : this.id || Roo.id()
47305 this.initEl(ct.createChild(o));
47307 this.root.render(this.el);
47311 this.items.each(function(f){
47312 f.render('x-form-el-'+f.id);
47315 if(this.buttons.length > 0){
47316 // tables are required to maintain order and for correct IE layout
47317 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47318 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47319 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47321 var tr = tb.getElementsByTagName('tr')[0];
47322 for(var i = 0, len = this.buttons.length; i < len; i++) {
47323 var b = this.buttons[i];
47324 var td = document.createElement('td');
47325 td.className = 'x-form-btn-td';
47326 b.render(tr.appendChild(td));
47329 if(this.monitorValid){ // initialize after render
47330 this.startMonitoring();
47332 this.fireEvent('rendered', this);
47337 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47338 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47339 * object or a valid Roo.DomHelper element config
47340 * @param {Function} handler The function called when the button is clicked
47341 * @param {Object} scope (optional) The scope of the handler function
47342 * @return {Roo.Button}
47344 addButton : function(config, handler, scope){
47348 minWidth: this.minButtonWidth,
47351 if(typeof config == "string"){
47354 Roo.apply(bc, config);
47356 var btn = new Roo.Button(null, bc);
47357 this.buttons.push(btn);
47362 * Adds a series of form elements (using the xtype property as the factory method.
47363 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47364 * @param {Object} config
47367 addxtype : function()
47369 var ar = Array.prototype.slice.call(arguments, 0);
47371 for(var i = 0; i < ar.length; i++) {
47373 continue; // skip -- if this happends something invalid got sent, we
47374 // should ignore it, as basically that interface element will not show up
47375 // and that should be pretty obvious!!
47378 if (Roo.form[ar[i].xtype]) {
47380 var fe = Roo.factory(ar[i], Roo.form);
47386 fe.store.form = this;
47391 this.allItems.push(fe);
47392 if (fe.items && fe.addxtype) {
47393 fe.addxtype.apply(fe, fe.items);
47403 // console.log('adding ' + ar[i].xtype);
47405 if (ar[i].xtype == 'Button') {
47406 //console.log('adding button');
47407 //console.log(ar[i]);
47408 this.addButton(ar[i]);
47409 this.allItems.push(fe);
47413 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47414 alert('end is not supported on xtype any more, use items');
47416 // //console.log('adding end');
47424 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47425 * option "monitorValid"
47427 startMonitoring : function(){
47430 Roo.TaskMgr.start({
47431 run : this.bindHandler,
47432 interval : this.monitorPoll || 200,
47439 * Stops monitoring of the valid state of this form
47441 stopMonitoring : function(){
47442 this.bound = false;
47446 bindHandler : function(){
47448 return false; // stops binding
47451 this.items.each(function(f){
47452 if(!f.isValid(true)){
47457 for(var i = 0, len = this.buttons.length; i < len; i++){
47458 var btn = this.buttons[i];
47459 if(btn.formBind === true && btn.disabled === valid){
47460 btn.setDisabled(!valid);
47463 this.fireEvent('clientvalidation', this, valid);
47477 Roo.Form = Roo.form.Form;
47480 * Ext JS Library 1.1.1
47481 * Copyright(c) 2006-2007, Ext JS, LLC.
47483 * Originally Released Under LGPL - original licence link has changed is not relivant.
47486 * <script type="text/javascript">
47489 // as we use this in bootstrap.
47490 Roo.namespace('Roo.form');
47492 * @class Roo.form.Action
47493 * Internal Class used to handle form actions
47495 * @param {Roo.form.BasicForm} el The form element or its id
47496 * @param {Object} config Configuration options
47501 // define the action interface
47502 Roo.form.Action = function(form, options){
47504 this.options = options || {};
47507 * Client Validation Failed
47510 Roo.form.Action.CLIENT_INVALID = 'client';
47512 * Server Validation Failed
47515 Roo.form.Action.SERVER_INVALID = 'server';
47517 * Connect to Server Failed
47520 Roo.form.Action.CONNECT_FAILURE = 'connect';
47522 * Reading Data from Server Failed
47525 Roo.form.Action.LOAD_FAILURE = 'load';
47527 Roo.form.Action.prototype = {
47529 failureType : undefined,
47530 response : undefined,
47531 result : undefined,
47533 // interface method
47534 run : function(options){
47538 // interface method
47539 success : function(response){
47543 // interface method
47544 handleResponse : function(response){
47548 // default connection failure
47549 failure : function(response){
47551 this.response = response;
47552 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47553 this.form.afterAction(this, false);
47556 processResponse : function(response){
47557 this.response = response;
47558 if(!response.responseText){
47561 this.result = this.handleResponse(response);
47562 return this.result;
47565 // utility functions used internally
47566 getUrl : function(appendParams){
47567 var url = this.options.url || this.form.url || this.form.el.dom.action;
47569 var p = this.getParams();
47571 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47577 getMethod : function(){
47578 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47581 getParams : function(){
47582 var bp = this.form.baseParams;
47583 var p = this.options.params;
47585 if(typeof p == "object"){
47586 p = Roo.urlEncode(Roo.applyIf(p, bp));
47587 }else if(typeof p == 'string' && bp){
47588 p += '&' + Roo.urlEncode(bp);
47591 p = Roo.urlEncode(bp);
47596 createCallback : function(){
47598 success: this.success,
47599 failure: this.failure,
47601 timeout: (this.form.timeout*1000),
47602 upload: this.form.fileUpload ? this.success : undefined
47607 Roo.form.Action.Submit = function(form, options){
47608 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47611 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47614 haveProgress : false,
47615 uploadComplete : false,
47617 // uploadProgress indicator.
47618 uploadProgress : function()
47620 if (!this.form.progressUrl) {
47624 if (!this.haveProgress) {
47625 Roo.MessageBox.progress("Uploading", "Uploading");
47627 if (this.uploadComplete) {
47628 Roo.MessageBox.hide();
47632 this.haveProgress = true;
47634 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47636 var c = new Roo.data.Connection();
47638 url : this.form.progressUrl,
47643 success : function(req){
47644 //console.log(data);
47648 rdata = Roo.decode(req.responseText)
47650 Roo.log("Invalid data from server..");
47654 if (!rdata || !rdata.success) {
47656 Roo.MessageBox.alert(Roo.encode(rdata));
47659 var data = rdata.data;
47661 if (this.uploadComplete) {
47662 Roo.MessageBox.hide();
47667 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47668 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47671 this.uploadProgress.defer(2000,this);
47674 failure: function(data) {
47675 Roo.log('progress url failed ');
47686 // run get Values on the form, so it syncs any secondary forms.
47687 this.form.getValues();
47689 var o = this.options;
47690 var method = this.getMethod();
47691 var isPost = method == 'POST';
47692 if(o.clientValidation === false || this.form.isValid()){
47694 if (this.form.progressUrl) {
47695 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47696 (new Date() * 1) + '' + Math.random());
47701 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47702 form:this.form.el.dom,
47703 url:this.getUrl(!isPost),
47705 params:isPost ? this.getParams() : null,
47706 isUpload: this.form.fileUpload
47709 this.uploadProgress();
47711 }else if (o.clientValidation !== false){ // client validation failed
47712 this.failureType = Roo.form.Action.CLIENT_INVALID;
47713 this.form.afterAction(this, false);
47717 success : function(response)
47719 this.uploadComplete= true;
47720 if (this.haveProgress) {
47721 Roo.MessageBox.hide();
47725 var result = this.processResponse(response);
47726 if(result === true || result.success){
47727 this.form.afterAction(this, true);
47731 this.form.markInvalid(result.errors);
47732 this.failureType = Roo.form.Action.SERVER_INVALID;
47734 this.form.afterAction(this, false);
47736 failure : function(response)
47738 this.uploadComplete= true;
47739 if (this.haveProgress) {
47740 Roo.MessageBox.hide();
47743 this.response = response;
47744 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47745 this.form.afterAction(this, false);
47748 handleResponse : function(response){
47749 if(this.form.errorReader){
47750 var rs = this.form.errorReader.read(response);
47753 for(var i = 0, len = rs.records.length; i < len; i++) {
47754 var r = rs.records[i];
47755 errors[i] = r.data;
47758 if(errors.length < 1){
47762 success : rs.success,
47768 ret = Roo.decode(response.responseText);
47772 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47782 Roo.form.Action.Load = function(form, options){
47783 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47784 this.reader = this.form.reader;
47787 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47792 Roo.Ajax.request(Roo.apply(
47793 this.createCallback(), {
47794 method:this.getMethod(),
47795 url:this.getUrl(false),
47796 params:this.getParams()
47800 success : function(response){
47802 var result = this.processResponse(response);
47803 if(result === true || !result.success || !result.data){
47804 this.failureType = Roo.form.Action.LOAD_FAILURE;
47805 this.form.afterAction(this, false);
47808 this.form.clearInvalid();
47809 this.form.setValues(result.data);
47810 this.form.afterAction(this, true);
47813 handleResponse : function(response){
47814 if(this.form.reader){
47815 var rs = this.form.reader.read(response);
47816 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47818 success : rs.success,
47822 return Roo.decode(response.responseText);
47826 Roo.form.Action.ACTION_TYPES = {
47827 'load' : Roo.form.Action.Load,
47828 'submit' : Roo.form.Action.Submit
47831 * Ext JS Library 1.1.1
47832 * Copyright(c) 2006-2007, Ext JS, LLC.
47834 * Originally Released Under LGPL - original licence link has changed is not relivant.
47837 * <script type="text/javascript">
47841 * @class Roo.form.Layout
47842 * @extends Roo.Component
47843 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47845 * @param {Object} config Configuration options
47847 Roo.form.Layout = function(config){
47849 if (config.items) {
47850 xitems = config.items;
47851 delete config.items;
47853 Roo.form.Layout.superclass.constructor.call(this, config);
47855 Roo.each(xitems, this.addxtype, this);
47859 Roo.extend(Roo.form.Layout, Roo.Component, {
47861 * @cfg {String/Object} autoCreate
47862 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
47865 * @cfg {String/Object/Function} style
47866 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
47867 * a function which returns such a specification.
47870 * @cfg {String} labelAlign
47871 * Valid values are "left," "top" and "right" (defaults to "left")
47874 * @cfg {Number} labelWidth
47875 * Fixed width in pixels of all field labels (defaults to undefined)
47878 * @cfg {Boolean} clear
47879 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
47883 * @cfg {String} labelSeparator
47884 * The separator to use after field labels (defaults to ':')
47886 labelSeparator : ':',
47888 * @cfg {Boolean} hideLabels
47889 * True to suppress the display of field labels in this layout (defaults to false)
47891 hideLabels : false,
47894 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
47899 onRender : function(ct, position){
47900 if(this.el){ // from markup
47901 this.el = Roo.get(this.el);
47902 }else { // generate
47903 var cfg = this.getAutoCreate();
47904 this.el = ct.createChild(cfg, position);
47907 this.el.applyStyles(this.style);
47909 if(this.labelAlign){
47910 this.el.addClass('x-form-label-'+this.labelAlign);
47912 if(this.hideLabels){
47913 this.labelStyle = "display:none";
47914 this.elementStyle = "padding-left:0;";
47916 if(typeof this.labelWidth == 'number'){
47917 this.labelStyle = "width:"+this.labelWidth+"px;";
47918 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
47920 if(this.labelAlign == 'top'){
47921 this.labelStyle = "width:auto;";
47922 this.elementStyle = "padding-left:0;";
47925 var stack = this.stack;
47926 var slen = stack.length;
47928 if(!this.fieldTpl){
47929 var t = new Roo.Template(
47930 '<div class="x-form-item {5}">',
47931 '<label for="{0}" style="{2}">{1}{4}</label>',
47932 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
47934 '</div><div class="x-form-clear-left"></div>'
47936 t.disableFormats = true;
47938 Roo.form.Layout.prototype.fieldTpl = t;
47940 for(var i = 0; i < slen; i++) {
47941 if(stack[i].isFormField){
47942 this.renderField(stack[i]);
47944 this.renderComponent(stack[i]);
47949 this.el.createChild({cls:'x-form-clear'});
47954 renderField : function(f){
47955 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
47958 f.labelStyle||this.labelStyle||'', //2
47959 this.elementStyle||'', //3
47960 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
47961 f.itemCls||this.itemCls||'' //5
47962 ], true).getPrevSibling());
47966 renderComponent : function(c){
47967 c.render(c.isLayout ? this.el : this.el.createChild());
47970 * Adds a object form elements (using the xtype property as the factory method.)
47971 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
47972 * @param {Object} config
47974 addxtype : function(o)
47976 // create the lement.
47977 o.form = this.form;
47978 var fe = Roo.factory(o, Roo.form);
47979 this.form.allItems.push(fe);
47980 this.stack.push(fe);
47982 if (fe.isFormField) {
47983 this.form.items.add(fe);
47991 * @class Roo.form.Column
47992 * @extends Roo.form.Layout
47993 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
47995 * @param {Object} config Configuration options
47997 Roo.form.Column = function(config){
47998 Roo.form.Column.superclass.constructor.call(this, config);
48001 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48003 * @cfg {Number/String} width
48004 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48007 * @cfg {String/Object} autoCreate
48008 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48012 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48015 onRender : function(ct, position){
48016 Roo.form.Column.superclass.onRender.call(this, ct, position);
48018 this.el.setWidth(this.width);
48025 * @class Roo.form.Row
48026 * @extends Roo.form.Layout
48027 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48029 * @param {Object} config Configuration options
48033 Roo.form.Row = function(config){
48034 Roo.form.Row.superclass.constructor.call(this, config);
48037 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48039 * @cfg {Number/String} width
48040 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48043 * @cfg {Number/String} height
48044 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48046 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48050 onRender : function(ct, position){
48051 //console.log('row render');
48053 var t = new Roo.Template(
48054 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48055 '<label for="{0}" style="{2}">{1}{4}</label>',
48056 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48060 t.disableFormats = true;
48062 Roo.form.Layout.prototype.rowTpl = t;
48064 this.fieldTpl = this.rowTpl;
48066 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48067 var labelWidth = 100;
48069 if ((this.labelAlign != 'top')) {
48070 if (typeof this.labelWidth == 'number') {
48071 labelWidth = this.labelWidth
48073 this.padWidth = 20 + labelWidth;
48077 Roo.form.Column.superclass.onRender.call(this, ct, position);
48079 this.el.setWidth(this.width);
48082 this.el.setHeight(this.height);
48087 renderField : function(f){
48088 f.fieldEl = this.fieldTpl.append(this.el, [
48089 f.id, f.fieldLabel,
48090 f.labelStyle||this.labelStyle||'',
48091 this.elementStyle||'',
48092 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48093 f.itemCls||this.itemCls||'',
48094 f.width ? f.width + this.padWidth : 160 + this.padWidth
48101 * @class Roo.form.FieldSet
48102 * @extends Roo.form.Layout
48103 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48105 * @param {Object} config Configuration options
48107 Roo.form.FieldSet = function(config){
48108 Roo.form.FieldSet.superclass.constructor.call(this, config);
48111 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48113 * @cfg {String} legend
48114 * The text to display as the legend for the FieldSet (defaults to '')
48117 * @cfg {String/Object} autoCreate
48118 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48122 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48125 onRender : function(ct, position){
48126 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48128 this.setLegend(this.legend);
48133 setLegend : function(text){
48135 this.el.child('legend').update(text);
48140 * Ext JS Library 1.1.1
48141 * Copyright(c) 2006-2007, Ext JS, LLC.
48143 * Originally Released Under LGPL - original licence link has changed is not relivant.
48146 * <script type="text/javascript">
48149 * @class Roo.form.VTypes
48150 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48153 Roo.form.VTypes = function(){
48154 // closure these in so they are only created once.
48155 var alpha = /^[a-zA-Z_]+$/;
48156 var alphanum = /^[a-zA-Z0-9_]+$/;
48157 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48158 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48160 // All these messages and functions are configurable
48163 * The function used to validate email addresses
48164 * @param {String} value The email address
48166 'email' : function(v){
48167 return email.test(v);
48170 * The error text to display when the email validation function returns false
48173 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48175 * The keystroke filter mask to be applied on email input
48178 'emailMask' : /[a-z0-9_\.\-@]/i,
48181 * The function used to validate URLs
48182 * @param {String} value The URL
48184 'url' : function(v){
48185 return url.test(v);
48188 * The error text to display when the url validation function returns false
48191 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48194 * The function used to validate alpha values
48195 * @param {String} value The value
48197 'alpha' : function(v){
48198 return alpha.test(v);
48201 * The error text to display when the alpha validation function returns false
48204 'alphaText' : 'This field should only contain letters and _',
48206 * The keystroke filter mask to be applied on alpha input
48209 'alphaMask' : /[a-z_]/i,
48212 * The function used to validate alphanumeric values
48213 * @param {String} value The value
48215 'alphanum' : function(v){
48216 return alphanum.test(v);
48219 * The error text to display when the alphanumeric validation function returns false
48222 'alphanumText' : 'This field should only contain letters, numbers and _',
48224 * The keystroke filter mask to be applied on alphanumeric input
48227 'alphanumMask' : /[a-z0-9_]/i
48229 }();//<script type="text/javascript">
48232 * @class Roo.form.FCKeditor
48233 * @extends Roo.form.TextArea
48234 * Wrapper around the FCKEditor http://www.fckeditor.net
48236 * Creates a new FCKeditor
48237 * @param {Object} config Configuration options
48239 Roo.form.FCKeditor = function(config){
48240 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48243 * @event editorinit
48244 * Fired when the editor is initialized - you can add extra handlers here..
48245 * @param {FCKeditor} this
48246 * @param {Object} the FCK object.
48253 Roo.form.FCKeditor.editors = { };
48254 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48256 //defaultAutoCreate : {
48257 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48261 * @cfg {Object} fck options - see fck manual for details.
48266 * @cfg {Object} fck toolbar set (Basic or Default)
48268 toolbarSet : 'Basic',
48270 * @cfg {Object} fck BasePath
48272 basePath : '/fckeditor/',
48280 onRender : function(ct, position)
48283 this.defaultAutoCreate = {
48285 style:"width:300px;height:60px;",
48286 autocomplete: "new-password"
48289 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48292 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48293 if(this.preventScrollbars){
48294 this.el.setStyle("overflow", "hidden");
48296 this.el.setHeight(this.growMin);
48299 //console.log('onrender' + this.getId() );
48300 Roo.form.FCKeditor.editors[this.getId()] = this;
48303 this.replaceTextarea() ;
48307 getEditor : function() {
48308 return this.fckEditor;
48311 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48312 * @param {Mixed} value The value to set
48316 setValue : function(value)
48318 //console.log('setValue: ' + value);
48320 if(typeof(value) == 'undefined') { // not sure why this is happending...
48323 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48325 //if(!this.el || !this.getEditor()) {
48326 // this.value = value;
48327 //this.setValue.defer(100,this,[value]);
48331 if(!this.getEditor()) {
48335 this.getEditor().SetData(value);
48342 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48343 * @return {Mixed} value The field value
48345 getValue : function()
48348 if (this.frame && this.frame.dom.style.display == 'none') {
48349 return Roo.form.FCKeditor.superclass.getValue.call(this);
48352 if(!this.el || !this.getEditor()) {
48354 // this.getValue.defer(100,this);
48359 var value=this.getEditor().GetData();
48360 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48361 return Roo.form.FCKeditor.superclass.getValue.call(this);
48367 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48368 * @return {Mixed} value The field value
48370 getRawValue : function()
48372 if (this.frame && this.frame.dom.style.display == 'none') {
48373 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48376 if(!this.el || !this.getEditor()) {
48377 //this.getRawValue.defer(100,this);
48384 var value=this.getEditor().GetData();
48385 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48386 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48390 setSize : function(w,h) {
48394 //if (this.frame && this.frame.dom.style.display == 'none') {
48395 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48398 //if(!this.el || !this.getEditor()) {
48399 // this.setSize.defer(100,this, [w,h]);
48405 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48407 this.frame.dom.setAttribute('width', w);
48408 this.frame.dom.setAttribute('height', h);
48409 this.frame.setSize(w,h);
48413 toggleSourceEdit : function(value) {
48417 this.el.dom.style.display = value ? '' : 'none';
48418 this.frame.dom.style.display = value ? 'none' : '';
48423 focus: function(tag)
48425 if (this.frame.dom.style.display == 'none') {
48426 return Roo.form.FCKeditor.superclass.focus.call(this);
48428 if(!this.el || !this.getEditor()) {
48429 this.focus.defer(100,this, [tag]);
48436 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48437 this.getEditor().Focus();
48439 if (!this.getEditor().Selection.GetSelection()) {
48440 this.focus.defer(100,this, [tag]);
48445 var r = this.getEditor().EditorDocument.createRange();
48446 r.setStart(tgs[0],0);
48447 r.setEnd(tgs[0],0);
48448 this.getEditor().Selection.GetSelection().removeAllRanges();
48449 this.getEditor().Selection.GetSelection().addRange(r);
48450 this.getEditor().Focus();
48457 replaceTextarea : function()
48459 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48462 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48464 // We must check the elements firstly using the Id and then the name.
48465 var oTextarea = document.getElementById( this.getId() );
48467 var colElementsByName = document.getElementsByName( this.getId() ) ;
48469 oTextarea.style.display = 'none' ;
48471 if ( oTextarea.tabIndex ) {
48472 this.TabIndex = oTextarea.tabIndex ;
48475 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48476 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48477 this.frame = Roo.get(this.getId() + '___Frame')
48480 _getConfigHtml : function()
48484 for ( var o in this.fckconfig ) {
48485 sConfig += sConfig.length > 0 ? '&' : '';
48486 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48489 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48493 _getIFrameHtml : function()
48495 var sFile = 'fckeditor.html' ;
48496 /* no idea what this is about..
48499 if ( (/fcksource=true/i).test( window.top.location.search ) )
48500 sFile = 'fckeditor.original.html' ;
48505 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48506 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48509 var html = '<iframe id="' + this.getId() +
48510 '___Frame" src="' + sLink +
48511 '" width="' + this.width +
48512 '" height="' + this.height + '"' +
48513 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48514 ' frameborder="0" scrolling="no"></iframe>' ;
48519 _insertHtmlBefore : function( html, element )
48521 if ( element.insertAdjacentHTML ) {
48523 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48525 var oRange = document.createRange() ;
48526 oRange.setStartBefore( element ) ;
48527 var oFragment = oRange.createContextualFragment( html );
48528 element.parentNode.insertBefore( oFragment, element ) ;
48541 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48543 function FCKeditor_OnComplete(editorInstance){
48544 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48545 f.fckEditor = editorInstance;
48546 //console.log("loaded");
48547 f.fireEvent('editorinit', f, editorInstance);
48567 //<script type="text/javascript">
48569 * @class Roo.form.GridField
48570 * @extends Roo.form.Field
48571 * Embed a grid (or editable grid into a form)
48574 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48576 * xgrid.store = Roo.data.Store
48577 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48578 * xgrid.store.reader = Roo.data.JsonReader
48582 * Creates a new GridField
48583 * @param {Object} config Configuration options
48585 Roo.form.GridField = function(config){
48586 Roo.form.GridField.superclass.constructor.call(this, config);
48590 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48592 * @cfg {Number} width - used to restrict width of grid..
48596 * @cfg {Number} height - used to restrict height of grid..
48600 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48606 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48607 * {tag: "input", type: "checkbox", autocomplete: "off"})
48609 // defaultAutoCreate : { tag: 'div' },
48610 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48612 * @cfg {String} addTitle Text to include for adding a title.
48616 onResize : function(){
48617 Roo.form.Field.superclass.onResize.apply(this, arguments);
48620 initEvents : function(){
48621 // Roo.form.Checkbox.superclass.initEvents.call(this);
48622 // has no events...
48627 getResizeEl : function(){
48631 getPositionEl : function(){
48636 onRender : function(ct, position){
48638 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48639 var style = this.style;
48642 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48643 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48644 this.viewEl = this.wrap.createChild({ tag: 'div' });
48646 this.viewEl.applyStyles(style);
48649 this.viewEl.setWidth(this.width);
48652 this.viewEl.setHeight(this.height);
48654 //if(this.inputValue !== undefined){
48655 //this.setValue(this.value);
48658 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48661 this.grid.render();
48662 this.grid.getDataSource().on('remove', this.refreshValue, this);
48663 this.grid.getDataSource().on('update', this.refreshValue, this);
48664 this.grid.on('afteredit', this.refreshValue, this);
48670 * Sets the value of the item.
48671 * @param {String} either an object or a string..
48673 setValue : function(v){
48675 v = v || []; // empty set..
48676 // this does not seem smart - it really only affects memoryproxy grids..
48677 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48678 var ds = this.grid.getDataSource();
48679 // assumes a json reader..
48681 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48682 ds.loadData( data);
48684 // clear selection so it does not get stale.
48685 if (this.grid.sm) {
48686 this.grid.sm.clearSelections();
48689 Roo.form.GridField.superclass.setValue.call(this, v);
48690 this.refreshValue();
48691 // should load data in the grid really....
48695 refreshValue: function() {
48697 this.grid.getDataSource().each(function(r) {
48700 this.el.dom.value = Roo.encode(val);
48708 * Ext JS Library 1.1.1
48709 * Copyright(c) 2006-2007, Ext JS, LLC.
48711 * Originally Released Under LGPL - original licence link has changed is not relivant.
48714 * <script type="text/javascript">
48717 * @class Roo.form.DisplayField
48718 * @extends Roo.form.Field
48719 * A generic Field to display non-editable data.
48720 * @cfg {Boolean} closable (true|false) default false
48722 * Creates a new Display Field item.
48723 * @param {Object} config Configuration options
48725 Roo.form.DisplayField = function(config){
48726 Roo.form.DisplayField.superclass.constructor.call(this, config);
48731 * Fires after the click the close btn
48732 * @param {Roo.form.DisplayField} this
48738 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48739 inputType: 'hidden',
48745 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48747 focusClass : undefined,
48749 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48751 fieldClass: 'x-form-field',
48754 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48756 valueRenderer: undefined,
48760 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48761 * {tag: "input", type: "checkbox", autocomplete: "off"})
48764 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48768 onResize : function(){
48769 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48773 initEvents : function(){
48774 // Roo.form.Checkbox.superclass.initEvents.call(this);
48775 // has no events...
48778 this.closeEl.on('click', this.onClose, this);
48784 getResizeEl : function(){
48788 getPositionEl : function(){
48793 onRender : function(ct, position){
48795 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48796 //if(this.inputValue !== undefined){
48797 this.wrap = this.el.wrap();
48799 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48802 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48805 if (this.bodyStyle) {
48806 this.viewEl.applyStyles(this.bodyStyle);
48808 //this.viewEl.setStyle('padding', '2px');
48810 this.setValue(this.value);
48815 initValue : Roo.emptyFn,
48820 onClick : function(){
48825 * Sets the checked state of the checkbox.
48826 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48828 setValue : function(v){
48830 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48831 // this might be called before we have a dom element..
48832 if (!this.viewEl) {
48835 this.viewEl.dom.innerHTML = html;
48836 Roo.form.DisplayField.superclass.setValue.call(this, v);
48840 onClose : function(e)
48842 e.preventDefault();
48844 this.fireEvent('close', this);
48853 * @class Roo.form.DayPicker
48854 * @extends Roo.form.Field
48855 * A Day picker show [M] [T] [W] ....
48857 * Creates a new Day Picker
48858 * @param {Object} config Configuration options
48860 Roo.form.DayPicker= function(config){
48861 Roo.form.DayPicker.superclass.constructor.call(this, config);
48865 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
48867 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48869 focusClass : undefined,
48871 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48873 fieldClass: "x-form-field",
48876 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48877 * {tag: "input", type: "checkbox", autocomplete: "off"})
48879 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
48882 actionMode : 'viewEl',
48886 inputType : 'hidden',
48889 inputElement: false, // real input element?
48890 basedOn: false, // ????
48892 isFormField: true, // not sure where this is needed!!!!
48894 onResize : function(){
48895 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
48896 if(!this.boxLabel){
48897 this.el.alignTo(this.wrap, 'c-c');
48901 initEvents : function(){
48902 Roo.form.Checkbox.superclass.initEvents.call(this);
48903 this.el.on("click", this.onClick, this);
48904 this.el.on("change", this.onClick, this);
48908 getResizeEl : function(){
48912 getPositionEl : function(){
48918 onRender : function(ct, position){
48919 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
48921 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
48923 var r1 = '<table><tr>';
48924 var r2 = '<tr class="x-form-daypick-icons">';
48925 for (var i=0; i < 7; i++) {
48926 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
48927 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
48930 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
48931 viewEl.select('img').on('click', this.onClick, this);
48932 this.viewEl = viewEl;
48935 // this will not work on Chrome!!!
48936 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
48937 this.el.on('propertychange', this.setFromHidden, this); //ie
48945 initValue : Roo.emptyFn,
48948 * Returns the checked state of the checkbox.
48949 * @return {Boolean} True if checked, else false
48951 getValue : function(){
48952 return this.el.dom.value;
48957 onClick : function(e){
48958 //this.setChecked(!this.checked);
48959 Roo.get(e.target).toggleClass('x-menu-item-checked');
48960 this.refreshValue();
48961 //if(this.el.dom.checked != this.checked){
48962 // this.setValue(this.el.dom.checked);
48967 refreshValue : function()
48970 this.viewEl.select('img',true).each(function(e,i,n) {
48971 val += e.is(".x-menu-item-checked") ? String(n) : '';
48973 this.setValue(val, true);
48977 * Sets the checked state of the checkbox.
48978 * On is always based on a string comparison between inputValue and the param.
48979 * @param {Boolean/String} value - the value to set
48980 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
48982 setValue : function(v,suppressEvent){
48983 if (!this.el.dom) {
48986 var old = this.el.dom.value ;
48987 this.el.dom.value = v;
48988 if (suppressEvent) {
48992 // update display..
48993 this.viewEl.select('img',true).each(function(e,i,n) {
48995 var on = e.is(".x-menu-item-checked");
48996 var newv = v.indexOf(String(n)) > -1;
48998 e.toggleClass('x-menu-item-checked');
49004 this.fireEvent('change', this, v, old);
49009 // handle setting of hidden value by some other method!!?!?
49010 setFromHidden: function()
49015 //console.log("SET FROM HIDDEN");
49016 //alert('setFrom hidden');
49017 this.setValue(this.el.dom.value);
49020 onDestroy : function()
49023 Roo.get(this.viewEl).remove();
49026 Roo.form.DayPicker.superclass.onDestroy.call(this);
49030 * RooJS Library 1.1.1
49031 * Copyright(c) 2008-2011 Alan Knowles
49038 * @class Roo.form.ComboCheck
49039 * @extends Roo.form.ComboBox
49040 * A combobox for multiple select items.
49042 * FIXME - could do with a reset button..
49045 * Create a new ComboCheck
49046 * @param {Object} config Configuration options
49048 Roo.form.ComboCheck = function(config){
49049 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49050 // should verify some data...
49052 // hiddenName = required..
49053 // displayField = required
49054 // valudField == required
49055 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49057 Roo.each(req, function(e) {
49058 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49059 throw "Roo.form.ComboCheck : missing value for: " + e;
49066 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49071 selectedClass: 'x-menu-item-checked',
49074 onRender : function(ct, position){
49080 var cls = 'x-combo-list';
49083 this.tpl = new Roo.Template({
49084 html : '<div class="'+cls+'-item x-menu-check-item">' +
49085 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49086 '<span>{' + this.displayField + '}</span>' +
49093 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49094 this.view.singleSelect = false;
49095 this.view.multiSelect = true;
49096 this.view.toggleSelect = true;
49097 this.pageTb.add(new Roo.Toolbar.Fill(), {
49100 handler: function()
49107 onViewOver : function(e, t){
49113 onViewClick : function(doFocus,index){
49117 select: function () {
49118 //Roo.log("SELECT CALLED");
49121 selectByValue : function(xv, scrollIntoView){
49122 var ar = this.getValueArray();
49125 Roo.each(ar, function(v) {
49126 if(v === undefined || v === null){
49129 var r = this.findRecord(this.valueField, v);
49131 sels.push(this.store.indexOf(r))
49135 this.view.select(sels);
49141 onSelect : function(record, index){
49142 // Roo.log("onselect Called");
49143 // this is only called by the clear button now..
49144 this.view.clearSelections();
49145 this.setValue('[]');
49146 if (this.value != this.valueBefore) {
49147 this.fireEvent('change', this, this.value, this.valueBefore);
49148 this.valueBefore = this.value;
49151 getValueArray : function()
49156 //Roo.log(this.value);
49157 if (typeof(this.value) == 'undefined') {
49160 var ar = Roo.decode(this.value);
49161 return ar instanceof Array ? ar : []; //?? valid?
49164 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49169 expand : function ()
49172 Roo.form.ComboCheck.superclass.expand.call(this);
49173 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49174 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49179 collapse : function(){
49180 Roo.form.ComboCheck.superclass.collapse.call(this);
49181 var sl = this.view.getSelectedIndexes();
49182 var st = this.store;
49186 Roo.each(sl, function(i) {
49188 nv.push(r.get(this.valueField));
49190 this.setValue(Roo.encode(nv));
49191 if (this.value != this.valueBefore) {
49193 this.fireEvent('change', this, this.value, this.valueBefore);
49194 this.valueBefore = this.value;
49199 setValue : function(v){
49203 var vals = this.getValueArray();
49205 Roo.each(vals, function(k) {
49206 var r = this.findRecord(this.valueField, k);
49208 tv.push(r.data[this.displayField]);
49209 }else if(this.valueNotFoundText !== undefined){
49210 tv.push( this.valueNotFoundText );
49215 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49216 this.hiddenField.value = v;
49222 * Ext JS Library 1.1.1
49223 * Copyright(c) 2006-2007, Ext JS, LLC.
49225 * Originally Released Under LGPL - original licence link has changed is not relivant.
49228 * <script type="text/javascript">
49232 * @class Roo.form.Signature
49233 * @extends Roo.form.Field
49237 * @param {Object} config Configuration options
49240 Roo.form.Signature = function(config){
49241 Roo.form.Signature.superclass.constructor.call(this, config);
49243 this.addEvents({// not in used??
49246 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49247 * @param {Roo.form.Signature} combo This combo box
49252 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49253 * @param {Roo.form.ComboBox} combo This combo box
49254 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49260 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49262 * @cfg {Object} labels Label to use when rendering a form.
49266 * confirm : "Confirm"
49271 confirm : "Confirm"
49274 * @cfg {Number} width The signature panel width (defaults to 300)
49278 * @cfg {Number} height The signature panel height (defaults to 100)
49282 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49284 allowBlank : false,
49287 // {Object} signPanel The signature SVG panel element (defaults to {})
49289 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49290 isMouseDown : false,
49291 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49292 isConfirmed : false,
49293 // {String} signatureTmp SVG mapping string (defaults to empty string)
49297 defaultAutoCreate : { // modified by initCompnoent..
49303 onRender : function(ct, position){
49305 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49307 this.wrap = this.el.wrap({
49308 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49311 this.createToolbar(this);
49312 this.signPanel = this.wrap.createChild({
49314 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49318 this.svgID = Roo.id();
49319 this.svgEl = this.signPanel.createChild({
49320 xmlns : 'http://www.w3.org/2000/svg',
49322 id : this.svgID + "-svg",
49324 height: this.height,
49325 viewBox: '0 0 '+this.width+' '+this.height,
49329 id: this.svgID + "-svg-r",
49331 height: this.height,
49336 id: this.svgID + "-svg-l",
49338 y1: (this.height*0.8), // start set the line in 80% of height
49339 x2: this.width, // end
49340 y2: (this.height*0.8), // end set the line in 80% of height
49342 'stroke-width': "1",
49343 'stroke-dasharray': "3",
49344 'shape-rendering': "crispEdges",
49345 'pointer-events': "none"
49349 id: this.svgID + "-svg-p",
49351 'stroke-width': "3",
49353 'pointer-events': 'none'
49358 this.svgBox = this.svgEl.dom.getScreenCTM();
49360 createSVG : function(){
49361 var svg = this.signPanel;
49362 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49365 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49366 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49367 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49368 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49369 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49370 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49371 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49374 isTouchEvent : function(e){
49375 return e.type.match(/^touch/);
49377 getCoords : function (e) {
49378 var pt = this.svgEl.dom.createSVGPoint();
49381 if (this.isTouchEvent(e)) {
49382 pt.x = e.targetTouches[0].clientX;
49383 pt.y = e.targetTouches[0].clientY;
49385 var a = this.svgEl.dom.getScreenCTM();
49386 var b = a.inverse();
49387 var mx = pt.matrixTransform(b);
49388 return mx.x + ',' + mx.y;
49390 //mouse event headler
49391 down : function (e) {
49392 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49393 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49395 this.isMouseDown = true;
49397 e.preventDefault();
49399 move : function (e) {
49400 if (this.isMouseDown) {
49401 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49402 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49405 e.preventDefault();
49407 up : function (e) {
49408 this.isMouseDown = false;
49409 var sp = this.signatureTmp.split(' ');
49412 if(!sp[sp.length-2].match(/^L/)){
49416 this.signatureTmp = sp.join(" ");
49419 if(this.getValue() != this.signatureTmp){
49420 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49421 this.isConfirmed = false;
49423 e.preventDefault();
49427 * Protected method that will not generally be called directly. It
49428 * is called when the editor creates its toolbar. Override this method if you need to
49429 * add custom toolbar buttons.
49430 * @param {HtmlEditor} editor
49432 createToolbar : function(editor){
49433 function btn(id, toggle, handler){
49434 var xid = fid + '-'+ id ;
49438 cls : 'x-btn-icon x-edit-'+id,
49439 enableToggle:toggle !== false,
49440 scope: editor, // was editor...
49441 handler:handler||editor.relayBtnCmd,
49442 clickEvent:'mousedown',
49443 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49449 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49453 cls : ' x-signature-btn x-signature-'+id,
49454 scope: editor, // was editor...
49455 handler: this.reset,
49456 clickEvent:'mousedown',
49457 text: this.labels.clear
49464 cls : ' x-signature-btn x-signature-'+id,
49465 scope: editor, // was editor...
49466 handler: this.confirmHandler,
49467 clickEvent:'mousedown',
49468 text: this.labels.confirm
49475 * when user is clicked confirm then show this image.....
49477 * @return {String} Image Data URI
49479 getImageDataURI : function(){
49480 var svg = this.svgEl.dom.parentNode.innerHTML;
49481 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49486 * @return {Boolean} this.isConfirmed
49488 getConfirmed : function(){
49489 return this.isConfirmed;
49493 * @return {Number} this.width
49495 getWidth : function(){
49500 * @return {Number} this.height
49502 getHeight : function(){
49503 return this.height;
49506 getSignature : function(){
49507 return this.signatureTmp;
49510 reset : function(){
49511 this.signatureTmp = '';
49512 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49513 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49514 this.isConfirmed = false;
49515 Roo.form.Signature.superclass.reset.call(this);
49517 setSignature : function(s){
49518 this.signatureTmp = s;
49519 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49520 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49522 this.isConfirmed = false;
49523 Roo.form.Signature.superclass.reset.call(this);
49526 // Roo.log(this.signPanel.dom.contentWindow.up())
49529 setConfirmed : function(){
49533 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49536 confirmHandler : function(){
49537 if(!this.getSignature()){
49541 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49542 this.setValue(this.getSignature());
49543 this.isConfirmed = true;
49545 this.fireEvent('confirm', this);
49548 // Subclasses should provide the validation implementation by overriding this
49549 validateValue : function(value){
49550 if(this.allowBlank){
49554 if(this.isConfirmed){
49561 * Ext JS Library 1.1.1
49562 * Copyright(c) 2006-2007, Ext JS, LLC.
49564 * Originally Released Under LGPL - original licence link has changed is not relivant.
49567 * <script type="text/javascript">
49572 * @class Roo.form.ComboBox
49573 * @extends Roo.form.TriggerField
49574 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49576 * Create a new ComboBox.
49577 * @param {Object} config Configuration options
49579 Roo.form.Select = function(config){
49580 Roo.form.Select.superclass.constructor.call(this, config);
49584 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49586 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49589 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49590 * rendering into an Roo.Editor, defaults to false)
49593 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49594 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49597 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49600 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49601 * the dropdown list (defaults to undefined, with no header element)
49605 * @cfg {String/Roo.Template} tpl The template to use to render the output
49609 defaultAutoCreate : {tag: "select" },
49611 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49613 listWidth: undefined,
49615 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49616 * mode = 'remote' or 'text' if mode = 'local')
49618 displayField: undefined,
49620 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49621 * mode = 'remote' or 'value' if mode = 'local').
49622 * Note: use of a valueField requires the user make a selection
49623 * in order for a value to be mapped.
49625 valueField: undefined,
49629 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49630 * field's data value (defaults to the underlying DOM element's name)
49632 hiddenName: undefined,
49634 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49638 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49640 selectedClass: 'x-combo-selected',
49642 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49643 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49644 * which displays a downward arrow icon).
49646 triggerClass : 'x-form-arrow-trigger',
49648 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49652 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49653 * anchor positions (defaults to 'tl-bl')
49655 listAlign: 'tl-bl?',
49657 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49661 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49662 * query specified by the allQuery config option (defaults to 'query')
49664 triggerAction: 'query',
49666 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49667 * (defaults to 4, does not apply if editable = false)
49671 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49672 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49676 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49677 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49681 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49682 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49686 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49687 * when editable = true (defaults to false)
49689 selectOnFocus:false,
49691 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49693 queryParam: 'query',
49695 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49696 * when mode = 'remote' (defaults to 'Loading...')
49698 loadingText: 'Loading...',
49700 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49704 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49708 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49709 * traditional select (defaults to true)
49713 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49717 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49721 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49722 * listWidth has a higher value)
49726 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49727 * allow the user to set arbitrary text into the field (defaults to false)
49729 forceSelection:false,
49731 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49732 * if typeAhead = true (defaults to 250)
49734 typeAheadDelay : 250,
49736 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49737 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49739 valueNotFoundText : undefined,
49742 * @cfg {String} defaultValue The value displayed after loading the store.
49747 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49749 blockFocus : false,
49752 * @cfg {Boolean} disableClear Disable showing of clear button.
49754 disableClear : false,
49756 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49758 alwaysQuery : false,
49764 // element that contains real text value.. (when hidden is used..)
49767 onRender : function(ct, position){
49768 Roo.form.Field.prototype.onRender.call(this, ct, position);
49771 this.store.on('beforeload', this.onBeforeLoad, this);
49772 this.store.on('load', this.onLoad, this);
49773 this.store.on('loadexception', this.onLoadException, this);
49774 this.store.load({});
49782 initEvents : function(){
49783 //Roo.form.ComboBox.superclass.initEvents.call(this);
49787 onDestroy : function(){
49790 this.store.un('beforeload', this.onBeforeLoad, this);
49791 this.store.un('load', this.onLoad, this);
49792 this.store.un('loadexception', this.onLoadException, this);
49794 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49798 fireKey : function(e){
49799 if(e.isNavKeyPress() && !this.list.isVisible()){
49800 this.fireEvent("specialkey", this, e);
49805 onResize: function(w, h){
49813 * Allow or prevent the user from directly editing the field text. If false is passed,
49814 * the user will only be able to select from the items defined in the dropdown list. This method
49815 * is the runtime equivalent of setting the 'editable' config option at config time.
49816 * @param {Boolean} value True to allow the user to directly edit the field text
49818 setEditable : function(value){
49823 onBeforeLoad : function(){
49825 Roo.log("Select before load");
49828 this.innerList.update(this.loadingText ?
49829 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49830 //this.restrictHeight();
49831 this.selectedIndex = -1;
49835 onLoad : function(){
49838 var dom = this.el.dom;
49839 dom.innerHTML = '';
49840 var od = dom.ownerDocument;
49842 if (this.emptyText) {
49843 var op = od.createElement('option');
49844 op.setAttribute('value', '');
49845 op.innerHTML = String.format('{0}', this.emptyText);
49846 dom.appendChild(op);
49848 if(this.store.getCount() > 0){
49850 var vf = this.valueField;
49851 var df = this.displayField;
49852 this.store.data.each(function(r) {
49853 // which colmsn to use... testing - cdoe / title..
49854 var op = od.createElement('option');
49855 op.setAttribute('value', r.data[vf]);
49856 op.innerHTML = String.format('{0}', r.data[df]);
49857 dom.appendChild(op);
49859 if (typeof(this.defaultValue != 'undefined')) {
49860 this.setValue(this.defaultValue);
49865 //this.onEmptyResults();
49870 onLoadException : function()
49872 dom.innerHTML = '';
49874 Roo.log("Select on load exception");
49878 Roo.log(this.store.reader.jsonData);
49879 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
49880 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
49886 onTypeAhead : function(){
49891 onSelect : function(record, index){
49892 Roo.log('on select?');
49894 if(this.fireEvent('beforeselect', this, record, index) !== false){
49895 this.setFromData(index > -1 ? record.data : false);
49897 this.fireEvent('select', this, record, index);
49902 * Returns the currently selected field value or empty string if no value is set.
49903 * @return {String} value The selected value
49905 getValue : function(){
49906 var dom = this.el.dom;
49907 this.value = dom.options[dom.selectedIndex].value;
49913 * Clears any text/value currently set in the field
49915 clearValue : function(){
49917 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
49922 * Sets the specified value into the field. If the value finds a match, the corresponding record text
49923 * will be displayed in the field. If the value does not match the data value of an existing item,
49924 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
49925 * Otherwise the field will be blank (although the value will still be set).
49926 * @param {String} value The value to match
49928 setValue : function(v){
49929 var d = this.el.dom;
49930 for (var i =0; i < d.options.length;i++) {
49931 if (v == d.options[i].value) {
49932 d.selectedIndex = i;
49940 * @property {Object} the last set data for the element
49945 * Sets the value of the field based on a object which is related to the record format for the store.
49946 * @param {Object} value the value to set as. or false on reset?
49948 setFromData : function(o){
49949 Roo.log('setfrom data?');
49955 reset : function(){
49959 findRecord : function(prop, value){
49964 if(this.store.getCount() > 0){
49965 this.store.each(function(r){
49966 if(r.data[prop] == value){
49976 getName: function()
49978 // returns hidden if it's set..
49979 if (!this.rendered) {return ''};
49980 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
49988 onEmptyResults : function(){
49989 Roo.log('empty results');
49994 * Returns true if the dropdown list is expanded, else false.
49996 isExpanded : function(){
50001 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50002 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50003 * @param {String} value The data value of the item to select
50004 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50005 * selected item if it is not currently in view (defaults to true)
50006 * @return {Boolean} True if the value matched an item in the list, else false
50008 selectByValue : function(v, scrollIntoView){
50009 Roo.log('select By Value');
50012 if(v !== undefined && v !== null){
50013 var r = this.findRecord(this.valueField || this.displayField, v);
50015 this.select(this.store.indexOf(r), scrollIntoView);
50023 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50024 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50025 * @param {Number} index The zero-based index of the list item to select
50026 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50027 * selected item if it is not currently in view (defaults to true)
50029 select : function(index, scrollIntoView){
50030 Roo.log('select ');
50033 this.selectedIndex = index;
50034 this.view.select(index);
50035 if(scrollIntoView !== false){
50036 var el = this.view.getNode(index);
50038 this.innerList.scrollChildIntoView(el, false);
50046 validateBlur : function(){
50053 initQuery : function(){
50054 this.doQuery(this.getRawValue());
50058 doForce : function(){
50059 if(this.el.dom.value.length > 0){
50060 this.el.dom.value =
50061 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50067 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50068 * query allowing the query action to be canceled if needed.
50069 * @param {String} query The SQL query to execute
50070 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50071 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50072 * saved in the current store (defaults to false)
50074 doQuery : function(q, forceAll){
50076 Roo.log('doQuery?');
50077 if(q === undefined || q === null){
50082 forceAll: forceAll,
50086 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50090 forceAll = qe.forceAll;
50091 if(forceAll === true || (q.length >= this.minChars)){
50092 if(this.lastQuery != q || this.alwaysQuery){
50093 this.lastQuery = q;
50094 if(this.mode == 'local'){
50095 this.selectedIndex = -1;
50097 this.store.clearFilter();
50099 this.store.filter(this.displayField, q);
50103 this.store.baseParams[this.queryParam] = q;
50105 params: this.getParams(q)
50110 this.selectedIndex = -1;
50117 getParams : function(q){
50119 //p[this.queryParam] = q;
50122 p.limit = this.pageSize;
50128 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50130 collapse : function(){
50135 collapseIf : function(e){
50140 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50142 expand : function(){
50150 * @cfg {Boolean} grow
50154 * @cfg {Number} growMin
50158 * @cfg {Number} growMax
50166 setWidth : function()
50170 getResizeEl : function(){
50173 });//<script type="text/javasscript">
50177 * @class Roo.DDView
50178 * A DnD enabled version of Roo.View.
50179 * @param {Element/String} container The Element in which to create the View.
50180 * @param {String} tpl The template string used to create the markup for each element of the View
50181 * @param {Object} config The configuration properties. These include all the config options of
50182 * {@link Roo.View} plus some specific to this class.<br>
50184 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50185 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50187 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50188 .x-view-drag-insert-above {
50189 border-top:1px dotted #3366cc;
50191 .x-view-drag-insert-below {
50192 border-bottom:1px dotted #3366cc;
50198 Roo.DDView = function(container, tpl, config) {
50199 Roo.DDView.superclass.constructor.apply(this, arguments);
50200 this.getEl().setStyle("outline", "0px none");
50201 this.getEl().unselectable();
50202 if (this.dragGroup) {
50203 this.setDraggable(this.dragGroup.split(","));
50205 if (this.dropGroup) {
50206 this.setDroppable(this.dropGroup.split(","));
50208 if (this.deletable) {
50209 this.setDeletable();
50211 this.isDirtyFlag = false;
50217 Roo.extend(Roo.DDView, Roo.View, {
50218 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50219 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50220 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50221 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50225 reset: Roo.emptyFn,
50227 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50229 validate: function() {
50233 destroy: function() {
50234 this.purgeListeners();
50235 this.getEl.removeAllListeners();
50236 this.getEl().remove();
50237 if (this.dragZone) {
50238 if (this.dragZone.destroy) {
50239 this.dragZone.destroy();
50242 if (this.dropZone) {
50243 if (this.dropZone.destroy) {
50244 this.dropZone.destroy();
50249 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50250 getName: function() {
50254 /** Loads the View from a JSON string representing the Records to put into the Store. */
50255 setValue: function(v) {
50257 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50260 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50261 this.store.proxy = new Roo.data.MemoryProxy(data);
50265 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50266 getValue: function() {
50268 this.store.each(function(rec) {
50269 result += rec.id + ',';
50271 return result.substr(0, result.length - 1) + ')';
50274 getIds: function() {
50275 var i = 0, result = new Array(this.store.getCount());
50276 this.store.each(function(rec) {
50277 result[i++] = rec.id;
50282 isDirty: function() {
50283 return this.isDirtyFlag;
50287 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50288 * whole Element becomes the target, and this causes the drop gesture to append.
50290 getTargetFromEvent : function(e) {
50291 var target = e.getTarget();
50292 while ((target !== null) && (target.parentNode != this.el.dom)) {
50293 target = target.parentNode;
50296 target = this.el.dom.lastChild || this.el.dom;
50302 * Create the drag data which consists of an object which has the property "ddel" as
50303 * the drag proxy element.
50305 getDragData : function(e) {
50306 var target = this.findItemFromChild(e.getTarget());
50308 this.handleSelection(e);
50309 var selNodes = this.getSelectedNodes();
50312 copy: this.copy || (this.allowCopy && e.ctrlKey),
50316 var selectedIndices = this.getSelectedIndexes();
50317 for (var i = 0; i < selectedIndices.length; i++) {
50318 dragData.records.push(this.store.getAt(selectedIndices[i]));
50320 if (selNodes.length == 1) {
50321 dragData.ddel = target.cloneNode(true); // the div element
50323 var div = document.createElement('div'); // create the multi element drag "ghost"
50324 div.className = 'multi-proxy';
50325 for (var i = 0, len = selNodes.length; i < len; i++) {
50326 div.appendChild(selNodes[i].cloneNode(true));
50328 dragData.ddel = div;
50330 //console.log(dragData)
50331 //console.log(dragData.ddel.innerHTML)
50334 //console.log('nodragData')
50338 /** Specify to which ddGroup items in this DDView may be dragged. */
50339 setDraggable: function(ddGroup) {
50340 if (ddGroup instanceof Array) {
50341 Roo.each(ddGroup, this.setDraggable, this);
50344 if (this.dragZone) {
50345 this.dragZone.addToGroup(ddGroup);
50347 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50348 containerScroll: true,
50352 // Draggability implies selection. DragZone's mousedown selects the element.
50353 if (!this.multiSelect) { this.singleSelect = true; }
50355 // Wire the DragZone's handlers up to methods in *this*
50356 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50360 /** Specify from which ddGroup this DDView accepts drops. */
50361 setDroppable: function(ddGroup) {
50362 if (ddGroup instanceof Array) {
50363 Roo.each(ddGroup, this.setDroppable, this);
50366 if (this.dropZone) {
50367 this.dropZone.addToGroup(ddGroup);
50369 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50370 containerScroll: true,
50374 // Wire the DropZone's handlers up to methods in *this*
50375 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50376 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50377 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50378 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50379 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50383 /** Decide whether to drop above or below a View node. */
50384 getDropPoint : function(e, n, dd){
50385 if (n == this.el.dom) { return "above"; }
50386 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50387 var c = t + (b - t) / 2;
50388 var y = Roo.lib.Event.getPageY(e);
50396 onNodeEnter : function(n, dd, e, data){
50400 onNodeOver : function(n, dd, e, data){
50401 var pt = this.getDropPoint(e, n, dd);
50402 // set the insert point style on the target node
50403 var dragElClass = this.dropNotAllowed;
50406 if (pt == "above"){
50407 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50408 targetElClass = "x-view-drag-insert-above";
50410 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50411 targetElClass = "x-view-drag-insert-below";
50413 if (this.lastInsertClass != targetElClass){
50414 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50415 this.lastInsertClass = targetElClass;
50418 return dragElClass;
50421 onNodeOut : function(n, dd, e, data){
50422 this.removeDropIndicators(n);
50425 onNodeDrop : function(n, dd, e, data){
50426 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50429 var pt = this.getDropPoint(e, n, dd);
50430 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50431 if (pt == "below") { insertAt++; }
50432 for (var i = 0; i < data.records.length; i++) {
50433 var r = data.records[i];
50434 var dup = this.store.getById(r.id);
50435 if (dup && (dd != this.dragZone)) {
50436 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50439 this.store.insert(insertAt++, r.copy());
50441 data.source.isDirtyFlag = true;
50443 this.store.insert(insertAt++, r);
50445 this.isDirtyFlag = true;
50448 this.dragZone.cachedTarget = null;
50452 removeDropIndicators : function(n){
50454 Roo.fly(n).removeClass([
50455 "x-view-drag-insert-above",
50456 "x-view-drag-insert-below"]);
50457 this.lastInsertClass = "_noclass";
50462 * Utility method. Add a delete option to the DDView's context menu.
50463 * @param {String} imageUrl The URL of the "delete" icon image.
50465 setDeletable: function(imageUrl) {
50466 if (!this.singleSelect && !this.multiSelect) {
50467 this.singleSelect = true;
50469 var c = this.getContextMenu();
50470 this.contextMenu.on("itemclick", function(item) {
50473 this.remove(this.getSelectedIndexes());
50477 this.contextMenu.add({
50484 /** Return the context menu for this DDView. */
50485 getContextMenu: function() {
50486 if (!this.contextMenu) {
50487 // Create the View's context menu
50488 this.contextMenu = new Roo.menu.Menu({
50489 id: this.id + "-contextmenu"
50491 this.el.on("contextmenu", this.showContextMenu, this);
50493 return this.contextMenu;
50496 disableContextMenu: function() {
50497 if (this.contextMenu) {
50498 this.el.un("contextmenu", this.showContextMenu, this);
50502 showContextMenu: function(e, item) {
50503 item = this.findItemFromChild(e.getTarget());
50506 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50507 this.contextMenu.showAt(e.getXY());
50512 * Remove {@link Roo.data.Record}s at the specified indices.
50513 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50515 remove: function(selectedIndices) {
50516 selectedIndices = [].concat(selectedIndices);
50517 for (var i = 0; i < selectedIndices.length; i++) {
50518 var rec = this.store.getAt(selectedIndices[i]);
50519 this.store.remove(rec);
50524 * Double click fires the event, but also, if this is draggable, and there is only one other
50525 * related DropZone, it transfers the selected node.
50527 onDblClick : function(e){
50528 var item = this.findItemFromChild(e.getTarget());
50530 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50533 if (this.dragGroup) {
50534 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50535 while (targets.indexOf(this.dropZone) > -1) {
50536 targets.remove(this.dropZone);
50538 if (targets.length == 1) {
50539 this.dragZone.cachedTarget = null;
50540 var el = Roo.get(targets[0].getEl());
50541 var box = el.getBox(true);
50542 targets[0].onNodeDrop(el.dom, {
50544 xy: [box.x, box.y + box.height - 1]
50545 }, null, this.getDragData(e));
50551 handleSelection: function(e) {
50552 this.dragZone.cachedTarget = null;
50553 var item = this.findItemFromChild(e.getTarget());
50555 this.clearSelections(true);
50558 if (item && (this.multiSelect || this.singleSelect)){
50559 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50560 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50561 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50562 this.unselect(item);
50564 this.select(item, this.multiSelect && e.ctrlKey);
50565 this.lastSelection = item;
50570 onItemClick : function(item, index, e){
50571 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50577 unselect : function(nodeInfo, suppressEvent){
50578 var node = this.getNode(nodeInfo);
50579 if(node && this.isSelected(node)){
50580 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50581 Roo.fly(node).removeClass(this.selectedClass);
50582 this.selections.remove(node);
50583 if(!suppressEvent){
50584 this.fireEvent("selectionchange", this, this.selections);
50592 * Ext JS Library 1.1.1
50593 * Copyright(c) 2006-2007, Ext JS, LLC.
50595 * Originally Released Under LGPL - original licence link has changed is not relivant.
50598 * <script type="text/javascript">
50602 * @class Roo.LayoutManager
50603 * @extends Roo.util.Observable
50604 * Base class for layout managers.
50606 Roo.LayoutManager = function(container, config){
50607 Roo.LayoutManager.superclass.constructor.call(this);
50608 this.el = Roo.get(container);
50609 // ie scrollbar fix
50610 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50611 document.body.scroll = "no";
50612 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50613 this.el.position('relative');
50615 this.id = this.el.id;
50616 this.el.addClass("x-layout-container");
50617 /** false to disable window resize monitoring @type Boolean */
50618 this.monitorWindowResize = true;
50623 * Fires when a layout is performed.
50624 * @param {Roo.LayoutManager} this
50628 * @event regionresized
50629 * Fires when the user resizes a region.
50630 * @param {Roo.LayoutRegion} region The resized region
50631 * @param {Number} newSize The new size (width for east/west, height for north/south)
50633 "regionresized" : true,
50635 * @event regioncollapsed
50636 * Fires when a region is collapsed.
50637 * @param {Roo.LayoutRegion} region The collapsed region
50639 "regioncollapsed" : true,
50641 * @event regionexpanded
50642 * Fires when a region is expanded.
50643 * @param {Roo.LayoutRegion} region The expanded region
50645 "regionexpanded" : true
50647 this.updating = false;
50648 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50651 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50653 * Returns true if this layout is currently being updated
50654 * @return {Boolean}
50656 isUpdating : function(){
50657 return this.updating;
50661 * Suspend the LayoutManager from doing auto-layouts while
50662 * making multiple add or remove calls
50664 beginUpdate : function(){
50665 this.updating = true;
50669 * Restore auto-layouts and optionally disable the manager from performing a layout
50670 * @param {Boolean} noLayout true to disable a layout update
50672 endUpdate : function(noLayout){
50673 this.updating = false;
50679 layout: function(){
50683 onRegionResized : function(region, newSize){
50684 this.fireEvent("regionresized", region, newSize);
50688 onRegionCollapsed : function(region){
50689 this.fireEvent("regioncollapsed", region);
50692 onRegionExpanded : function(region){
50693 this.fireEvent("regionexpanded", region);
50697 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50698 * performs box-model adjustments.
50699 * @return {Object} The size as an object {width: (the width), height: (the height)}
50701 getViewSize : function(){
50703 if(this.el.dom != document.body){
50704 size = this.el.getSize();
50706 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50708 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50709 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50714 * Returns the Element this layout is bound to.
50715 * @return {Roo.Element}
50717 getEl : function(){
50722 * Returns the specified region.
50723 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50724 * @return {Roo.LayoutRegion}
50726 getRegion : function(target){
50727 return this.regions[target.toLowerCase()];
50730 onWindowResize : function(){
50731 if(this.monitorWindowResize){
50737 * Ext JS Library 1.1.1
50738 * Copyright(c) 2006-2007, Ext JS, LLC.
50740 * Originally Released Under LGPL - original licence link has changed is not relivant.
50743 * <script type="text/javascript">
50746 * @class Roo.BorderLayout
50747 * @extends Roo.LayoutManager
50748 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50749 * please see: <br><br>
50750 * <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>
50751 * <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>
50754 var layout = new Roo.BorderLayout(document.body, {
50788 preferredTabWidth: 150
50793 var CP = Roo.ContentPanel;
50795 layout.beginUpdate();
50796 layout.add("north", new CP("north", "North"));
50797 layout.add("south", new CP("south", {title: "South", closable: true}));
50798 layout.add("west", new CP("west", {title: "West"}));
50799 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50800 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50801 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50802 layout.getRegion("center").showPanel("center1");
50803 layout.endUpdate();
50806 <b>The container the layout is rendered into can be either the body element or any other element.
50807 If it is not the body element, the container needs to either be an absolute positioned element,
50808 or you will need to add "position:relative" to the css of the container. You will also need to specify
50809 the container size if it is not the body element.</b>
50812 * Create a new BorderLayout
50813 * @param {String/HTMLElement/Element} container The container this layout is bound to
50814 * @param {Object} config Configuration options
50816 Roo.BorderLayout = function(container, config){
50817 config = config || {};
50818 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50819 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50820 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50821 var target = this.factory.validRegions[i];
50822 if(config[target]){
50823 this.addRegion(target, config[target]);
50828 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50830 * Creates and adds a new region if it doesn't already exist.
50831 * @param {String} target The target region key (north, south, east, west or center).
50832 * @param {Object} config The regions config object
50833 * @return {BorderLayoutRegion} The new region
50835 addRegion : function(target, config){
50836 if(!this.regions[target]){
50837 var r = this.factory.create(target, this, config);
50838 this.bindRegion(target, r);
50840 return this.regions[target];
50844 bindRegion : function(name, r){
50845 this.regions[name] = r;
50846 r.on("visibilitychange", this.layout, this);
50847 r.on("paneladded", this.layout, this);
50848 r.on("panelremoved", this.layout, this);
50849 r.on("invalidated", this.layout, this);
50850 r.on("resized", this.onRegionResized, this);
50851 r.on("collapsed", this.onRegionCollapsed, this);
50852 r.on("expanded", this.onRegionExpanded, this);
50856 * Performs a layout update.
50858 layout : function(){
50859 if(this.updating) {
50862 var size = this.getViewSize();
50863 var w = size.width;
50864 var h = size.height;
50869 //var x = 0, y = 0;
50871 var rs = this.regions;
50872 var north = rs["north"];
50873 var south = rs["south"];
50874 var west = rs["west"];
50875 var east = rs["east"];
50876 var center = rs["center"];
50877 //if(this.hideOnLayout){ // not supported anymore
50878 //c.el.setStyle("display", "none");
50880 if(north && north.isVisible()){
50881 var b = north.getBox();
50882 var m = north.getMargins();
50883 b.width = w - (m.left+m.right);
50886 centerY = b.height + b.y + m.bottom;
50887 centerH -= centerY;
50888 north.updateBox(this.safeBox(b));
50890 if(south && south.isVisible()){
50891 var b = south.getBox();
50892 var m = south.getMargins();
50893 b.width = w - (m.left+m.right);
50895 var totalHeight = (b.height + m.top + m.bottom);
50896 b.y = h - totalHeight + m.top;
50897 centerH -= totalHeight;
50898 south.updateBox(this.safeBox(b));
50900 if(west && west.isVisible()){
50901 var b = west.getBox();
50902 var m = west.getMargins();
50903 b.height = centerH - (m.top+m.bottom);
50905 b.y = centerY + m.top;
50906 var totalWidth = (b.width + m.left + m.right);
50907 centerX += totalWidth;
50908 centerW -= totalWidth;
50909 west.updateBox(this.safeBox(b));
50911 if(east && east.isVisible()){
50912 var b = east.getBox();
50913 var m = east.getMargins();
50914 b.height = centerH - (m.top+m.bottom);
50915 var totalWidth = (b.width + m.left + m.right);
50916 b.x = w - totalWidth + m.left;
50917 b.y = centerY + m.top;
50918 centerW -= totalWidth;
50919 east.updateBox(this.safeBox(b));
50922 var m = center.getMargins();
50924 x: centerX + m.left,
50925 y: centerY + m.top,
50926 width: centerW - (m.left+m.right),
50927 height: centerH - (m.top+m.bottom)
50929 //if(this.hideOnLayout){
50930 //center.el.setStyle("display", "block");
50932 center.updateBox(this.safeBox(centerBox));
50935 this.fireEvent("layout", this);
50939 safeBox : function(box){
50940 box.width = Math.max(0, box.width);
50941 box.height = Math.max(0, box.height);
50946 * Adds a ContentPanel (or subclass) to this layout.
50947 * @param {String} target The target region key (north, south, east, west or center).
50948 * @param {Roo.ContentPanel} panel The panel to add
50949 * @return {Roo.ContentPanel} The added panel
50951 add : function(target, panel){
50953 target = target.toLowerCase();
50954 return this.regions[target].add(panel);
50958 * Remove a ContentPanel (or subclass) to this layout.
50959 * @param {String} target The target region key (north, south, east, west or center).
50960 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
50961 * @return {Roo.ContentPanel} The removed panel
50963 remove : function(target, panel){
50964 target = target.toLowerCase();
50965 return this.regions[target].remove(panel);
50969 * Searches all regions for a panel with the specified id
50970 * @param {String} panelId
50971 * @return {Roo.ContentPanel} The panel or null if it wasn't found
50973 findPanel : function(panelId){
50974 var rs = this.regions;
50975 for(var target in rs){
50976 if(typeof rs[target] != "function"){
50977 var p = rs[target].getPanel(panelId);
50987 * Searches all regions for a panel with the specified id and activates (shows) it.
50988 * @param {String/ContentPanel} panelId The panels id or the panel itself
50989 * @return {Roo.ContentPanel} The shown panel or null
50991 showPanel : function(panelId) {
50992 var rs = this.regions;
50993 for(var target in rs){
50994 var r = rs[target];
50995 if(typeof r != "function"){
50996 if(r.hasPanel(panelId)){
50997 return r.showPanel(panelId);
51005 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51006 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51008 restoreState : function(provider){
51010 provider = Roo.state.Manager;
51012 var sm = new Roo.LayoutStateManager();
51013 sm.init(this, provider);
51017 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51018 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51019 * a valid ContentPanel config object. Example:
51021 // Create the main layout
51022 var layout = new Roo.BorderLayout('main-ct', {
51033 // Create and add multiple ContentPanels at once via configs
51036 id: 'source-files',
51038 title:'Ext Source Files',
51051 * @param {Object} regions An object containing ContentPanel configs by region name
51053 batchAdd : function(regions){
51054 this.beginUpdate();
51055 for(var rname in regions){
51056 var lr = this.regions[rname];
51058 this.addTypedPanels(lr, regions[rname]);
51065 addTypedPanels : function(lr, ps){
51066 if(typeof ps == 'string'){
51067 lr.add(new Roo.ContentPanel(ps));
51069 else if(ps instanceof Array){
51070 for(var i =0, len = ps.length; i < len; i++){
51071 this.addTypedPanels(lr, ps[i]);
51074 else if(!ps.events){ // raw config?
51076 delete ps.el; // prevent conflict
51077 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51079 else { // panel object assumed!
51084 * Adds a xtype elements to the layout.
51088 xtype : 'ContentPanel',
51095 xtype : 'NestedLayoutPanel',
51101 items : [ ... list of content panels or nested layout panels.. ]
51105 * @param {Object} cfg Xtype definition of item to add.
51107 addxtype : function(cfg)
51109 // basically accepts a pannel...
51110 // can accept a layout region..!?!?
51111 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51113 if (!cfg.xtype.match(/Panel$/)) {
51118 if (typeof(cfg.region) == 'undefined') {
51119 Roo.log("Failed to add Panel, region was not set");
51123 var region = cfg.region;
51129 xitems = cfg.items;
51136 case 'ContentPanel': // ContentPanel (el, cfg)
51137 case 'ScrollPanel': // ContentPanel (el, cfg)
51139 if(cfg.autoCreate) {
51140 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51142 var el = this.el.createChild();
51143 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51146 this.add(region, ret);
51150 case 'TreePanel': // our new panel!
51151 cfg.el = this.el.createChild();
51152 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51153 this.add(region, ret);
51156 case 'NestedLayoutPanel':
51157 // create a new Layout (which is a Border Layout...
51158 var el = this.el.createChild();
51159 var clayout = cfg.layout;
51161 clayout.items = clayout.items || [];
51162 // replace this exitems with the clayout ones..
51163 xitems = clayout.items;
51166 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51167 cfg.background = false;
51169 var layout = new Roo.BorderLayout(el, clayout);
51171 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51172 //console.log('adding nested layout panel ' + cfg.toSource());
51173 this.add(region, ret);
51174 nb = {}; /// find first...
51179 // needs grid and region
51181 //var el = this.getRegion(region).el.createChild();
51182 var el = this.el.createChild();
51183 // create the grid first...
51185 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51187 if (region == 'center' && this.active ) {
51188 cfg.background = false;
51190 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51192 this.add(region, ret);
51193 if (cfg.background) {
51194 ret.on('activate', function(gp) {
51195 if (!gp.grid.rendered) {
51210 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51212 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51213 this.add(region, ret);
51216 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51220 // GridPanel (grid, cfg)
51223 this.beginUpdate();
51227 Roo.each(xitems, function(i) {
51228 region = nb && i.region ? i.region : false;
51230 var add = ret.addxtype(i);
51233 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51234 if (!i.background) {
51235 abn[region] = nb[region] ;
51242 // make the last non-background panel active..
51243 //if (nb) { Roo.log(abn); }
51246 for(var r in abn) {
51247 region = this.getRegion(r);
51249 // tried using nb[r], but it does not work..
51251 region.showPanel(abn[r]);
51262 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51263 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51264 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51265 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51268 var CP = Roo.ContentPanel;
51270 var layout = Roo.BorderLayout.create({
51274 panels: [new CP("north", "North")]
51283 panels: [new CP("west", {title: "West"})]
51292 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51301 panels: [new CP("south", {title: "South", closable: true})]
51308 preferredTabWidth: 150,
51310 new CP("center1", {title: "Close Me", closable: true}),
51311 new CP("center2", {title: "Center Panel", closable: false})
51316 layout.getRegion("center").showPanel("center1");
51321 Roo.BorderLayout.create = function(config, targetEl){
51322 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51323 layout.beginUpdate();
51324 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51325 for(var j = 0, jlen = regions.length; j < jlen; j++){
51326 var lr = regions[j];
51327 if(layout.regions[lr] && config[lr].panels){
51328 var r = layout.regions[lr];
51329 var ps = config[lr].panels;
51330 layout.addTypedPanels(r, ps);
51333 layout.endUpdate();
51338 Roo.BorderLayout.RegionFactory = {
51340 validRegions : ["north","south","east","west","center"],
51343 create : function(target, mgr, config){
51344 target = target.toLowerCase();
51345 if(config.lightweight || config.basic){
51346 return new Roo.BasicLayoutRegion(mgr, config, target);
51350 return new Roo.NorthLayoutRegion(mgr, config);
51352 return new Roo.SouthLayoutRegion(mgr, config);
51354 return new Roo.EastLayoutRegion(mgr, config);
51356 return new Roo.WestLayoutRegion(mgr, config);
51358 return new Roo.CenterLayoutRegion(mgr, config);
51360 throw 'Layout region "'+target+'" not supported.';
51364 * Ext JS Library 1.1.1
51365 * Copyright(c) 2006-2007, Ext JS, LLC.
51367 * Originally Released Under LGPL - original licence link has changed is not relivant.
51370 * <script type="text/javascript">
51374 * @class Roo.BasicLayoutRegion
51375 * @extends Roo.util.Observable
51376 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51377 * and does not have a titlebar, tabs or any other features. All it does is size and position
51378 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51380 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51382 this.position = pos;
51385 * @scope Roo.BasicLayoutRegion
51389 * @event beforeremove
51390 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51391 * @param {Roo.LayoutRegion} this
51392 * @param {Roo.ContentPanel} panel The panel
51393 * @param {Object} e The cancel event object
51395 "beforeremove" : true,
51397 * @event invalidated
51398 * Fires when the layout for this region is changed.
51399 * @param {Roo.LayoutRegion} this
51401 "invalidated" : true,
51403 * @event visibilitychange
51404 * Fires when this region is shown or hidden
51405 * @param {Roo.LayoutRegion} this
51406 * @param {Boolean} visibility true or false
51408 "visibilitychange" : true,
51410 * @event paneladded
51411 * Fires when a panel is added.
51412 * @param {Roo.LayoutRegion} this
51413 * @param {Roo.ContentPanel} panel The panel
51415 "paneladded" : true,
51417 * @event panelremoved
51418 * Fires when a panel is removed.
51419 * @param {Roo.LayoutRegion} this
51420 * @param {Roo.ContentPanel} panel The panel
51422 "panelremoved" : true,
51425 * Fires when this region is collapsed.
51426 * @param {Roo.LayoutRegion} this
51428 "collapsed" : true,
51431 * Fires when this region is expanded.
51432 * @param {Roo.LayoutRegion} this
51437 * Fires when this region is slid into view.
51438 * @param {Roo.LayoutRegion} this
51440 "slideshow" : true,
51443 * Fires when this region slides out of view.
51444 * @param {Roo.LayoutRegion} this
51446 "slidehide" : true,
51448 * @event panelactivated
51449 * Fires when a panel is activated.
51450 * @param {Roo.LayoutRegion} this
51451 * @param {Roo.ContentPanel} panel The activated panel
51453 "panelactivated" : true,
51456 * Fires when the user resizes this region.
51457 * @param {Roo.LayoutRegion} this
51458 * @param {Number} newSize The new size (width for east/west, height for north/south)
51462 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51463 this.panels = new Roo.util.MixedCollection();
51464 this.panels.getKey = this.getPanelId.createDelegate(this);
51466 this.activePanel = null;
51467 // ensure listeners are added...
51469 if (config.listeners || config.events) {
51470 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51471 listeners : config.listeners || {},
51472 events : config.events || {}
51476 if(skipConfig !== true){
51477 this.applyConfig(config);
51481 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51482 getPanelId : function(p){
51486 applyConfig : function(config){
51487 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51488 this.config = config;
51493 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51494 * the width, for horizontal (north, south) the height.
51495 * @param {Number} newSize The new width or height
51497 resizeTo : function(newSize){
51498 var el = this.el ? this.el :
51499 (this.activePanel ? this.activePanel.getEl() : null);
51501 switch(this.position){
51504 el.setWidth(newSize);
51505 this.fireEvent("resized", this, newSize);
51509 el.setHeight(newSize);
51510 this.fireEvent("resized", this, newSize);
51516 getBox : function(){
51517 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51520 getMargins : function(){
51521 return this.margins;
51524 updateBox : function(box){
51526 var el = this.activePanel.getEl();
51527 el.dom.style.left = box.x + "px";
51528 el.dom.style.top = box.y + "px";
51529 this.activePanel.setSize(box.width, box.height);
51533 * Returns the container element for this region.
51534 * @return {Roo.Element}
51536 getEl : function(){
51537 return this.activePanel;
51541 * Returns true if this region is currently visible.
51542 * @return {Boolean}
51544 isVisible : function(){
51545 return this.activePanel ? true : false;
51548 setActivePanel : function(panel){
51549 panel = this.getPanel(panel);
51550 if(this.activePanel && this.activePanel != panel){
51551 this.activePanel.setActiveState(false);
51552 this.activePanel.getEl().setLeftTop(-10000,-10000);
51554 this.activePanel = panel;
51555 panel.setActiveState(true);
51557 panel.setSize(this.box.width, this.box.height);
51559 this.fireEvent("panelactivated", this, panel);
51560 this.fireEvent("invalidated");
51564 * Show the specified panel.
51565 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51566 * @return {Roo.ContentPanel} The shown panel or null
51568 showPanel : function(panel){
51569 if(panel = this.getPanel(panel)){
51570 this.setActivePanel(panel);
51576 * Get the active panel for this region.
51577 * @return {Roo.ContentPanel} The active panel or null
51579 getActivePanel : function(){
51580 return this.activePanel;
51584 * Add the passed ContentPanel(s)
51585 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51586 * @return {Roo.ContentPanel} The panel added (if only one was added)
51588 add : function(panel){
51589 if(arguments.length > 1){
51590 for(var i = 0, len = arguments.length; i < len; i++) {
51591 this.add(arguments[i]);
51595 if(this.hasPanel(panel)){
51596 this.showPanel(panel);
51599 var el = panel.getEl();
51600 if(el.dom.parentNode != this.mgr.el.dom){
51601 this.mgr.el.dom.appendChild(el.dom);
51603 if(panel.setRegion){
51604 panel.setRegion(this);
51606 this.panels.add(panel);
51607 el.setStyle("position", "absolute");
51608 if(!panel.background){
51609 this.setActivePanel(panel);
51610 if(this.config.initialSize && this.panels.getCount()==1){
51611 this.resizeTo(this.config.initialSize);
51614 this.fireEvent("paneladded", this, panel);
51619 * Returns true if the panel is in this region.
51620 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51621 * @return {Boolean}
51623 hasPanel : function(panel){
51624 if(typeof panel == "object"){ // must be panel obj
51625 panel = panel.getId();
51627 return this.getPanel(panel) ? true : false;
51631 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51632 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51633 * @param {Boolean} preservePanel Overrides the config preservePanel option
51634 * @return {Roo.ContentPanel} The panel that was removed
51636 remove : function(panel, preservePanel){
51637 panel = this.getPanel(panel);
51642 this.fireEvent("beforeremove", this, panel, e);
51643 if(e.cancel === true){
51646 var panelId = panel.getId();
51647 this.panels.removeKey(panelId);
51652 * Returns the panel specified or null if it's not in this region.
51653 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51654 * @return {Roo.ContentPanel}
51656 getPanel : function(id){
51657 if(typeof id == "object"){ // must be panel obj
51660 return this.panels.get(id);
51664 * Returns this regions position (north/south/east/west/center).
51667 getPosition: function(){
51668 return this.position;
51672 * Ext JS Library 1.1.1
51673 * Copyright(c) 2006-2007, Ext JS, LLC.
51675 * Originally Released Under LGPL - original licence link has changed is not relivant.
51678 * <script type="text/javascript">
51682 * @class Roo.LayoutRegion
51683 * @extends Roo.BasicLayoutRegion
51684 * This class represents a region in a layout manager.
51685 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51686 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51687 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51688 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51689 * @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})
51690 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51691 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51692 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51693 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51694 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51695 * @cfg {String} title The title for the region (overrides panel titles)
51696 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51697 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51698 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51699 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51700 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51701 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51702 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51703 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51704 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51705 * @cfg {Boolean} showPin True to show a pin button
51706 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51707 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51708 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51709 * @cfg {Number} width For East/West panels
51710 * @cfg {Number} height For North/South panels
51711 * @cfg {Boolean} split To show the splitter
51712 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51714 Roo.LayoutRegion = function(mgr, config, pos){
51715 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51716 var dh = Roo.DomHelper;
51717 /** This region's container element
51718 * @type Roo.Element */
51719 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51720 /** This region's title element
51721 * @type Roo.Element */
51723 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51724 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51725 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51727 this.titleEl.enableDisplayMode();
51728 /** This region's title text element
51729 * @type HTMLElement */
51730 this.titleTextEl = this.titleEl.dom.firstChild;
51731 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51732 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51733 this.closeBtn.enableDisplayMode();
51734 this.closeBtn.on("click", this.closeClicked, this);
51735 this.closeBtn.hide();
51737 this.createBody(config);
51738 this.visible = true;
51739 this.collapsed = false;
51741 if(config.hideWhenEmpty){
51743 this.on("paneladded", this.validateVisibility, this);
51744 this.on("panelremoved", this.validateVisibility, this);
51746 this.applyConfig(config);
51749 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51751 createBody : function(){
51752 /** This region's body element
51753 * @type Roo.Element */
51754 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51757 applyConfig : function(c){
51758 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51759 var dh = Roo.DomHelper;
51760 if(c.titlebar !== false){
51761 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51762 this.collapseBtn.on("click", this.collapse, this);
51763 this.collapseBtn.enableDisplayMode();
51765 if(c.showPin === true || this.showPin){
51766 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51767 this.stickBtn.enableDisplayMode();
51768 this.stickBtn.on("click", this.expand, this);
51769 this.stickBtn.hide();
51772 /** This region's collapsed element
51773 * @type Roo.Element */
51774 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51775 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51777 if(c.floatable !== false){
51778 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51779 this.collapsedEl.on("click", this.collapseClick, this);
51782 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51783 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51784 id: "message", unselectable: "on", style:{"float":"left"}});
51785 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51787 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51788 this.expandBtn.on("click", this.expand, this);
51790 if(this.collapseBtn){
51791 this.collapseBtn.setVisible(c.collapsible == true);
51793 this.cmargins = c.cmargins || this.cmargins ||
51794 (this.position == "west" || this.position == "east" ?
51795 {top: 0, left: 2, right:2, bottom: 0} :
51796 {top: 2, left: 0, right:0, bottom: 2});
51797 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51798 this.bottomTabs = c.tabPosition != "top";
51799 this.autoScroll = c.autoScroll || false;
51800 if(this.autoScroll){
51801 this.bodyEl.setStyle("overflow", "auto");
51803 this.bodyEl.setStyle("overflow", "hidden");
51805 //if(c.titlebar !== false){
51806 if((!c.titlebar && !c.title) || c.titlebar === false){
51807 this.titleEl.hide();
51809 this.titleEl.show();
51811 this.titleTextEl.innerHTML = c.title;
51815 this.duration = c.duration || .30;
51816 this.slideDuration = c.slideDuration || .45;
51819 this.collapse(true);
51826 * Returns true if this region is currently visible.
51827 * @return {Boolean}
51829 isVisible : function(){
51830 return this.visible;
51834 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51835 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51837 setCollapsedTitle : function(title){
51838 title = title || " ";
51839 if(this.collapsedTitleTextEl){
51840 this.collapsedTitleTextEl.innerHTML = title;
51844 getBox : function(){
51846 if(!this.collapsed){
51847 b = this.el.getBox(false, true);
51849 b = this.collapsedEl.getBox(false, true);
51854 getMargins : function(){
51855 return this.collapsed ? this.cmargins : this.margins;
51858 highlight : function(){
51859 this.el.addClass("x-layout-panel-dragover");
51862 unhighlight : function(){
51863 this.el.removeClass("x-layout-panel-dragover");
51866 updateBox : function(box){
51868 if(!this.collapsed){
51869 this.el.dom.style.left = box.x + "px";
51870 this.el.dom.style.top = box.y + "px";
51871 this.updateBody(box.width, box.height);
51873 this.collapsedEl.dom.style.left = box.x + "px";
51874 this.collapsedEl.dom.style.top = box.y + "px";
51875 this.collapsedEl.setSize(box.width, box.height);
51878 this.tabs.autoSizeTabs();
51882 updateBody : function(w, h){
51884 this.el.setWidth(w);
51885 w -= this.el.getBorderWidth("rl");
51886 if(this.config.adjustments){
51887 w += this.config.adjustments[0];
51891 this.el.setHeight(h);
51892 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
51893 h -= this.el.getBorderWidth("tb");
51894 if(this.config.adjustments){
51895 h += this.config.adjustments[1];
51897 this.bodyEl.setHeight(h);
51899 h = this.tabs.syncHeight(h);
51902 if(this.panelSize){
51903 w = w !== null ? w : this.panelSize.width;
51904 h = h !== null ? h : this.panelSize.height;
51906 if(this.activePanel){
51907 var el = this.activePanel.getEl();
51908 w = w !== null ? w : el.getWidth();
51909 h = h !== null ? h : el.getHeight();
51910 this.panelSize = {width: w, height: h};
51911 this.activePanel.setSize(w, h);
51913 if(Roo.isIE && this.tabs){
51914 this.tabs.el.repaint();
51919 * Returns the container element for this region.
51920 * @return {Roo.Element}
51922 getEl : function(){
51927 * Hides this region.
51930 if(!this.collapsed){
51931 this.el.dom.style.left = "-2000px";
51934 this.collapsedEl.dom.style.left = "-2000px";
51935 this.collapsedEl.hide();
51937 this.visible = false;
51938 this.fireEvent("visibilitychange", this, false);
51942 * Shows this region if it was previously hidden.
51945 if(!this.collapsed){
51948 this.collapsedEl.show();
51950 this.visible = true;
51951 this.fireEvent("visibilitychange", this, true);
51954 closeClicked : function(){
51955 if(this.activePanel){
51956 this.remove(this.activePanel);
51960 collapseClick : function(e){
51962 e.stopPropagation();
51965 e.stopPropagation();
51971 * Collapses this region.
51972 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
51974 collapse : function(skipAnim){
51975 if(this.collapsed) {
51978 this.collapsed = true;
51980 this.split.el.hide();
51982 if(this.config.animate && skipAnim !== true){
51983 this.fireEvent("invalidated", this);
51984 this.animateCollapse();
51986 this.el.setLocation(-20000,-20000);
51988 this.collapsedEl.show();
51989 this.fireEvent("collapsed", this);
51990 this.fireEvent("invalidated", this);
51994 animateCollapse : function(){
51999 * Expands this region if it was previously collapsed.
52000 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52001 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52003 expand : function(e, skipAnim){
52005 e.stopPropagation();
52007 if(!this.collapsed || this.el.hasActiveFx()) {
52011 this.afterSlideIn();
52014 this.collapsed = false;
52015 if(this.config.animate && skipAnim !== true){
52016 this.animateExpand();
52020 this.split.el.show();
52022 this.collapsedEl.setLocation(-2000,-2000);
52023 this.collapsedEl.hide();
52024 this.fireEvent("invalidated", this);
52025 this.fireEvent("expanded", this);
52029 animateExpand : function(){
52033 initTabs : function()
52035 this.bodyEl.setStyle("overflow", "hidden");
52036 var ts = new Roo.TabPanel(
52039 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52040 disableTooltips: this.config.disableTabTips,
52041 toolbar : this.config.toolbar
52044 if(this.config.hideTabs){
52045 ts.stripWrap.setDisplayed(false);
52048 ts.resizeTabs = this.config.resizeTabs === true;
52049 ts.minTabWidth = this.config.minTabWidth || 40;
52050 ts.maxTabWidth = this.config.maxTabWidth || 250;
52051 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52052 ts.monitorResize = false;
52053 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52054 ts.bodyEl.addClass('x-layout-tabs-body');
52055 this.panels.each(this.initPanelAsTab, this);
52058 initPanelAsTab : function(panel){
52059 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52060 this.config.closeOnTab && panel.isClosable());
52061 if(panel.tabTip !== undefined){
52062 ti.setTooltip(panel.tabTip);
52064 ti.on("activate", function(){
52065 this.setActivePanel(panel);
52067 if(this.config.closeOnTab){
52068 ti.on("beforeclose", function(t, e){
52070 this.remove(panel);
52076 updatePanelTitle : function(panel, title){
52077 if(this.activePanel == panel){
52078 this.updateTitle(title);
52081 var ti = this.tabs.getTab(panel.getEl().id);
52083 if(panel.tabTip !== undefined){
52084 ti.setTooltip(panel.tabTip);
52089 updateTitle : function(title){
52090 if(this.titleTextEl && !this.config.title){
52091 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52095 setActivePanel : function(panel){
52096 panel = this.getPanel(panel);
52097 if(this.activePanel && this.activePanel != panel){
52098 this.activePanel.setActiveState(false);
52100 this.activePanel = panel;
52101 panel.setActiveState(true);
52102 if(this.panelSize){
52103 panel.setSize(this.panelSize.width, this.panelSize.height);
52106 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52108 this.updateTitle(panel.getTitle());
52110 this.fireEvent("invalidated", this);
52112 this.fireEvent("panelactivated", this, panel);
52116 * Shows the specified panel.
52117 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52118 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52120 showPanel : function(panel)
52122 panel = this.getPanel(panel);
52125 var tab = this.tabs.getTab(panel.getEl().id);
52126 if(tab.isHidden()){
52127 this.tabs.unhideTab(tab.id);
52131 this.setActivePanel(panel);
52138 * Get the active panel for this region.
52139 * @return {Roo.ContentPanel} The active panel or null
52141 getActivePanel : function(){
52142 return this.activePanel;
52145 validateVisibility : function(){
52146 if(this.panels.getCount() < 1){
52147 this.updateTitle(" ");
52148 this.closeBtn.hide();
52151 if(!this.isVisible()){
52158 * Adds the passed ContentPanel(s) to this region.
52159 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52160 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52162 add : function(panel){
52163 if(arguments.length > 1){
52164 for(var i = 0, len = arguments.length; i < len; i++) {
52165 this.add(arguments[i]);
52169 if(this.hasPanel(panel)){
52170 this.showPanel(panel);
52173 panel.setRegion(this);
52174 this.panels.add(panel);
52175 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52176 this.bodyEl.dom.appendChild(panel.getEl().dom);
52177 if(panel.background !== true){
52178 this.setActivePanel(panel);
52180 this.fireEvent("paneladded", this, panel);
52186 this.initPanelAsTab(panel);
52188 if(panel.background !== true){
52189 this.tabs.activate(panel.getEl().id);
52191 this.fireEvent("paneladded", this, panel);
52196 * Hides the tab for the specified panel.
52197 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52199 hidePanel : function(panel){
52200 if(this.tabs && (panel = this.getPanel(panel))){
52201 this.tabs.hideTab(panel.getEl().id);
52206 * Unhides the tab for a previously hidden panel.
52207 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52209 unhidePanel : function(panel){
52210 if(this.tabs && (panel = this.getPanel(panel))){
52211 this.tabs.unhideTab(panel.getEl().id);
52215 clearPanels : function(){
52216 while(this.panels.getCount() > 0){
52217 this.remove(this.panels.first());
52222 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52223 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52224 * @param {Boolean} preservePanel Overrides the config preservePanel option
52225 * @return {Roo.ContentPanel} The panel that was removed
52227 remove : function(panel, preservePanel){
52228 panel = this.getPanel(panel);
52233 this.fireEvent("beforeremove", this, panel, e);
52234 if(e.cancel === true){
52237 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52238 var panelId = panel.getId();
52239 this.panels.removeKey(panelId);
52241 document.body.appendChild(panel.getEl().dom);
52244 this.tabs.removeTab(panel.getEl().id);
52245 }else if (!preservePanel){
52246 this.bodyEl.dom.removeChild(panel.getEl().dom);
52248 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52249 var p = this.panels.first();
52250 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52251 tempEl.appendChild(p.getEl().dom);
52252 this.bodyEl.update("");
52253 this.bodyEl.dom.appendChild(p.getEl().dom);
52255 this.updateTitle(p.getTitle());
52257 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52258 this.setActivePanel(p);
52260 panel.setRegion(null);
52261 if(this.activePanel == panel){
52262 this.activePanel = null;
52264 if(this.config.autoDestroy !== false && preservePanel !== true){
52265 try{panel.destroy();}catch(e){}
52267 this.fireEvent("panelremoved", this, panel);
52272 * Returns the TabPanel component used by this region
52273 * @return {Roo.TabPanel}
52275 getTabs : function(){
52279 createTool : function(parentEl, className){
52280 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52281 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52282 btn.addClassOnOver("x-layout-tools-button-over");
52287 * Ext JS Library 1.1.1
52288 * Copyright(c) 2006-2007, Ext JS, LLC.
52290 * Originally Released Under LGPL - original licence link has changed is not relivant.
52293 * <script type="text/javascript">
52299 * @class Roo.SplitLayoutRegion
52300 * @extends Roo.LayoutRegion
52301 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52303 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52304 this.cursor = cursor;
52305 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52308 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52309 splitTip : "Drag to resize.",
52310 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52311 useSplitTips : false,
52313 applyConfig : function(config){
52314 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52317 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52318 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52319 /** The SplitBar for this region
52320 * @type Roo.SplitBar */
52321 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52322 this.split.on("moved", this.onSplitMove, this);
52323 this.split.useShim = config.useShim === true;
52324 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52325 if(this.useSplitTips){
52326 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52328 if(config.collapsible){
52329 this.split.el.on("dblclick", this.collapse, this);
52332 if(typeof config.minSize != "undefined"){
52333 this.split.minSize = config.minSize;
52335 if(typeof config.maxSize != "undefined"){
52336 this.split.maxSize = config.maxSize;
52338 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52339 this.hideSplitter();
52344 getHMaxSize : function(){
52345 var cmax = this.config.maxSize || 10000;
52346 var center = this.mgr.getRegion("center");
52347 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52350 getVMaxSize : function(){
52351 var cmax = this.config.maxSize || 10000;
52352 var center = this.mgr.getRegion("center");
52353 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52356 onSplitMove : function(split, newSize){
52357 this.fireEvent("resized", this, newSize);
52361 * Returns the {@link Roo.SplitBar} for this region.
52362 * @return {Roo.SplitBar}
52364 getSplitBar : function(){
52369 this.hideSplitter();
52370 Roo.SplitLayoutRegion.superclass.hide.call(this);
52373 hideSplitter : function(){
52375 this.split.el.setLocation(-2000,-2000);
52376 this.split.el.hide();
52382 this.split.el.show();
52384 Roo.SplitLayoutRegion.superclass.show.call(this);
52387 beforeSlide: function(){
52388 if(Roo.isGecko){// firefox overflow auto bug workaround
52389 this.bodyEl.clip();
52391 this.tabs.bodyEl.clip();
52393 if(this.activePanel){
52394 this.activePanel.getEl().clip();
52396 if(this.activePanel.beforeSlide){
52397 this.activePanel.beforeSlide();
52403 afterSlide : function(){
52404 if(Roo.isGecko){// firefox overflow auto bug workaround
52405 this.bodyEl.unclip();
52407 this.tabs.bodyEl.unclip();
52409 if(this.activePanel){
52410 this.activePanel.getEl().unclip();
52411 if(this.activePanel.afterSlide){
52412 this.activePanel.afterSlide();
52418 initAutoHide : function(){
52419 if(this.autoHide !== false){
52420 if(!this.autoHideHd){
52421 var st = new Roo.util.DelayedTask(this.slideIn, this);
52422 this.autoHideHd = {
52423 "mouseout": function(e){
52424 if(!e.within(this.el, true)){
52428 "mouseover" : function(e){
52434 this.el.on(this.autoHideHd);
52438 clearAutoHide : function(){
52439 if(this.autoHide !== false){
52440 this.el.un("mouseout", this.autoHideHd.mouseout);
52441 this.el.un("mouseover", this.autoHideHd.mouseover);
52445 clearMonitor : function(){
52446 Roo.get(document).un("click", this.slideInIf, this);
52449 // these names are backwards but not changed for compat
52450 slideOut : function(){
52451 if(this.isSlid || this.el.hasActiveFx()){
52454 this.isSlid = true;
52455 if(this.collapseBtn){
52456 this.collapseBtn.hide();
52458 this.closeBtnState = this.closeBtn.getStyle('display');
52459 this.closeBtn.hide();
52461 this.stickBtn.show();
52464 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52465 this.beforeSlide();
52466 this.el.setStyle("z-index", 10001);
52467 this.el.slideIn(this.getSlideAnchor(), {
52468 callback: function(){
52470 this.initAutoHide();
52471 Roo.get(document).on("click", this.slideInIf, this);
52472 this.fireEvent("slideshow", this);
52479 afterSlideIn : function(){
52480 this.clearAutoHide();
52481 this.isSlid = false;
52482 this.clearMonitor();
52483 this.el.setStyle("z-index", "");
52484 if(this.collapseBtn){
52485 this.collapseBtn.show();
52487 this.closeBtn.setStyle('display', this.closeBtnState);
52489 this.stickBtn.hide();
52491 this.fireEvent("slidehide", this);
52494 slideIn : function(cb){
52495 if(!this.isSlid || this.el.hasActiveFx()){
52499 this.isSlid = false;
52500 this.beforeSlide();
52501 this.el.slideOut(this.getSlideAnchor(), {
52502 callback: function(){
52503 this.el.setLeftTop(-10000, -10000);
52505 this.afterSlideIn();
52513 slideInIf : function(e){
52514 if(!e.within(this.el)){
52519 animateCollapse : function(){
52520 this.beforeSlide();
52521 this.el.setStyle("z-index", 20000);
52522 var anchor = this.getSlideAnchor();
52523 this.el.slideOut(anchor, {
52524 callback : function(){
52525 this.el.setStyle("z-index", "");
52526 this.collapsedEl.slideIn(anchor, {duration:.3});
52528 this.el.setLocation(-10000,-10000);
52530 this.fireEvent("collapsed", this);
52537 animateExpand : function(){
52538 this.beforeSlide();
52539 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52540 this.el.setStyle("z-index", 20000);
52541 this.collapsedEl.hide({
52544 this.el.slideIn(this.getSlideAnchor(), {
52545 callback : function(){
52546 this.el.setStyle("z-index", "");
52549 this.split.el.show();
52551 this.fireEvent("invalidated", this);
52552 this.fireEvent("expanded", this);
52580 getAnchor : function(){
52581 return this.anchors[this.position];
52584 getCollapseAnchor : function(){
52585 return this.canchors[this.position];
52588 getSlideAnchor : function(){
52589 return this.sanchors[this.position];
52592 getAlignAdj : function(){
52593 var cm = this.cmargins;
52594 switch(this.position){
52610 getExpandAdj : function(){
52611 var c = this.collapsedEl, cm = this.cmargins;
52612 switch(this.position){
52614 return [-(cm.right+c.getWidth()+cm.left), 0];
52617 return [cm.right+c.getWidth()+cm.left, 0];
52620 return [0, -(cm.top+cm.bottom+c.getHeight())];
52623 return [0, cm.top+cm.bottom+c.getHeight()];
52629 * Ext JS Library 1.1.1
52630 * Copyright(c) 2006-2007, Ext JS, LLC.
52632 * Originally Released Under LGPL - original licence link has changed is not relivant.
52635 * <script type="text/javascript">
52638 * These classes are private internal classes
52640 Roo.CenterLayoutRegion = function(mgr, config){
52641 Roo.LayoutRegion.call(this, mgr, config, "center");
52642 this.visible = true;
52643 this.minWidth = config.minWidth || 20;
52644 this.minHeight = config.minHeight || 20;
52647 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52649 // center panel can't be hidden
52653 // center panel can't be hidden
52656 getMinWidth: function(){
52657 return this.minWidth;
52660 getMinHeight: function(){
52661 return this.minHeight;
52666 Roo.NorthLayoutRegion = function(mgr, config){
52667 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52669 this.split.placement = Roo.SplitBar.TOP;
52670 this.split.orientation = Roo.SplitBar.VERTICAL;
52671 this.split.el.addClass("x-layout-split-v");
52673 var size = config.initialSize || config.height;
52674 if(typeof size != "undefined"){
52675 this.el.setHeight(size);
52678 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52679 orientation: Roo.SplitBar.VERTICAL,
52680 getBox : function(){
52681 if(this.collapsed){
52682 return this.collapsedEl.getBox();
52684 var box = this.el.getBox();
52686 box.height += this.split.el.getHeight();
52691 updateBox : function(box){
52692 if(this.split && !this.collapsed){
52693 box.height -= this.split.el.getHeight();
52694 this.split.el.setLeft(box.x);
52695 this.split.el.setTop(box.y+box.height);
52696 this.split.el.setWidth(box.width);
52698 if(this.collapsed){
52699 this.updateBody(box.width, null);
52701 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52705 Roo.SouthLayoutRegion = function(mgr, config){
52706 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52708 this.split.placement = Roo.SplitBar.BOTTOM;
52709 this.split.orientation = Roo.SplitBar.VERTICAL;
52710 this.split.el.addClass("x-layout-split-v");
52712 var size = config.initialSize || config.height;
52713 if(typeof size != "undefined"){
52714 this.el.setHeight(size);
52717 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52718 orientation: Roo.SplitBar.VERTICAL,
52719 getBox : function(){
52720 if(this.collapsed){
52721 return this.collapsedEl.getBox();
52723 var box = this.el.getBox();
52725 var sh = this.split.el.getHeight();
52732 updateBox : function(box){
52733 if(this.split && !this.collapsed){
52734 var sh = this.split.el.getHeight();
52737 this.split.el.setLeft(box.x);
52738 this.split.el.setTop(box.y-sh);
52739 this.split.el.setWidth(box.width);
52741 if(this.collapsed){
52742 this.updateBody(box.width, null);
52744 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52748 Roo.EastLayoutRegion = function(mgr, config){
52749 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52751 this.split.placement = Roo.SplitBar.RIGHT;
52752 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52753 this.split.el.addClass("x-layout-split-h");
52755 var size = config.initialSize || config.width;
52756 if(typeof size != "undefined"){
52757 this.el.setWidth(size);
52760 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52761 orientation: Roo.SplitBar.HORIZONTAL,
52762 getBox : function(){
52763 if(this.collapsed){
52764 return this.collapsedEl.getBox();
52766 var box = this.el.getBox();
52768 var sw = this.split.el.getWidth();
52775 updateBox : function(box){
52776 if(this.split && !this.collapsed){
52777 var sw = this.split.el.getWidth();
52779 this.split.el.setLeft(box.x);
52780 this.split.el.setTop(box.y);
52781 this.split.el.setHeight(box.height);
52784 if(this.collapsed){
52785 this.updateBody(null, box.height);
52787 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52791 Roo.WestLayoutRegion = function(mgr, config){
52792 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52794 this.split.placement = Roo.SplitBar.LEFT;
52795 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52796 this.split.el.addClass("x-layout-split-h");
52798 var size = config.initialSize || config.width;
52799 if(typeof size != "undefined"){
52800 this.el.setWidth(size);
52803 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52804 orientation: Roo.SplitBar.HORIZONTAL,
52805 getBox : function(){
52806 if(this.collapsed){
52807 return this.collapsedEl.getBox();
52809 var box = this.el.getBox();
52811 box.width += this.split.el.getWidth();
52816 updateBox : function(box){
52817 if(this.split && !this.collapsed){
52818 var sw = this.split.el.getWidth();
52820 this.split.el.setLeft(box.x+box.width);
52821 this.split.el.setTop(box.y);
52822 this.split.el.setHeight(box.height);
52824 if(this.collapsed){
52825 this.updateBody(null, box.height);
52827 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52832 * Ext JS Library 1.1.1
52833 * Copyright(c) 2006-2007, Ext JS, LLC.
52835 * Originally Released Under LGPL - original licence link has changed is not relivant.
52838 * <script type="text/javascript">
52843 * Private internal class for reading and applying state
52845 Roo.LayoutStateManager = function(layout){
52846 // default empty state
52855 Roo.LayoutStateManager.prototype = {
52856 init : function(layout, provider){
52857 this.provider = provider;
52858 var state = provider.get(layout.id+"-layout-state");
52860 var wasUpdating = layout.isUpdating();
52862 layout.beginUpdate();
52864 for(var key in state){
52865 if(typeof state[key] != "function"){
52866 var rstate = state[key];
52867 var r = layout.getRegion(key);
52870 r.resizeTo(rstate.size);
52872 if(rstate.collapsed == true){
52875 r.expand(null, true);
52881 layout.endUpdate();
52883 this.state = state;
52885 this.layout = layout;
52886 layout.on("regionresized", this.onRegionResized, this);
52887 layout.on("regioncollapsed", this.onRegionCollapsed, this);
52888 layout.on("regionexpanded", this.onRegionExpanded, this);
52891 storeState : function(){
52892 this.provider.set(this.layout.id+"-layout-state", this.state);
52895 onRegionResized : function(region, newSize){
52896 this.state[region.getPosition()].size = newSize;
52900 onRegionCollapsed : function(region){
52901 this.state[region.getPosition()].collapsed = true;
52905 onRegionExpanded : function(region){
52906 this.state[region.getPosition()].collapsed = false;
52911 * Ext JS Library 1.1.1
52912 * Copyright(c) 2006-2007, Ext JS, LLC.
52914 * Originally Released Under LGPL - original licence link has changed is not relivant.
52917 * <script type="text/javascript">
52920 * @class Roo.ContentPanel
52921 * @extends Roo.util.Observable
52922 * A basic ContentPanel element.
52923 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
52924 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
52925 * @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
52926 * @cfg {Boolean} closable True if the panel can be closed/removed
52927 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
52928 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
52929 * @cfg {Toolbar} toolbar A toolbar for this panel
52930 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
52931 * @cfg {String} title The title for this panel
52932 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
52933 * @cfg {String} url Calls {@link #setUrl} with this value
52934 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
52935 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
52936 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
52937 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
52940 * Create a new ContentPanel.
52941 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
52942 * @param {String/Object} config A string to set only the title or a config object
52943 * @param {String} content (optional) Set the HTML content for this panel
52944 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
52946 Roo.ContentPanel = function(el, config, content){
52950 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
52954 if (config && config.parentLayout) {
52955 el = config.parentLayout.el.createChild();
52958 if(el.autoCreate){ // xtype is available if this is called from factory
52962 this.el = Roo.get(el);
52963 if(!this.el && config && config.autoCreate){
52964 if(typeof config.autoCreate == "object"){
52965 if(!config.autoCreate.id){
52966 config.autoCreate.id = config.id||el;
52968 this.el = Roo.DomHelper.append(document.body,
52969 config.autoCreate, true);
52971 this.el = Roo.DomHelper.append(document.body,
52972 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
52975 this.closable = false;
52976 this.loaded = false;
52977 this.active = false;
52978 if(typeof config == "string"){
52979 this.title = config;
52981 Roo.apply(this, config);
52984 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
52985 this.wrapEl = this.el.wrap();
52986 this.toolbar.container = this.el.insertSibling(false, 'before');
52987 this.toolbar = new Roo.Toolbar(this.toolbar);
52990 // xtype created footer. - not sure if will work as we normally have to render first..
52991 if (this.footer && !this.footer.el && this.footer.xtype) {
52992 if (!this.wrapEl) {
52993 this.wrapEl = this.el.wrap();
52996 this.footer.container = this.wrapEl.createChild();
52998 this.footer = Roo.factory(this.footer, Roo);
53003 this.resizeEl = Roo.get(this.resizeEl, true);
53005 this.resizeEl = this.el;
53007 // handle view.xtype
53015 * Fires when this panel is activated.
53016 * @param {Roo.ContentPanel} this
53020 * @event deactivate
53021 * Fires when this panel is activated.
53022 * @param {Roo.ContentPanel} this
53024 "deactivate" : true,
53028 * Fires when this panel is resized if fitToFrame is true.
53029 * @param {Roo.ContentPanel} this
53030 * @param {Number} width The width after any component adjustments
53031 * @param {Number} height The height after any component adjustments
53037 * Fires when this tab is created
53038 * @param {Roo.ContentPanel} this
53049 if(this.autoScroll){
53050 this.resizeEl.setStyle("overflow", "auto");
53052 // fix randome scrolling
53053 this.el.on('scroll', function() {
53054 Roo.log('fix random scolling');
53055 this.scrollTo('top',0);
53058 content = content || this.content;
53060 this.setContent(content);
53062 if(config && config.url){
53063 this.setUrl(this.url, this.params, this.loadOnce);
53068 Roo.ContentPanel.superclass.constructor.call(this);
53070 if (this.view && typeof(this.view.xtype) != 'undefined') {
53071 this.view.el = this.el.appendChild(document.createElement("div"));
53072 this.view = Roo.factory(this.view);
53073 this.view.render && this.view.render(false, '');
53077 this.fireEvent('render', this);
53080 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53082 setRegion : function(region){
53083 this.region = region;
53085 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53087 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53092 * Returns the toolbar for this Panel if one was configured.
53093 * @return {Roo.Toolbar}
53095 getToolbar : function(){
53096 return this.toolbar;
53099 setActiveState : function(active){
53100 this.active = active;
53102 this.fireEvent("deactivate", this);
53104 this.fireEvent("activate", this);
53108 * Updates this panel's element
53109 * @param {String} content The new content
53110 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53112 setContent : function(content, loadScripts){
53113 this.el.update(content, loadScripts);
53116 ignoreResize : function(w, h){
53117 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53120 this.lastSize = {width: w, height: h};
53125 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53126 * @return {Roo.UpdateManager} The UpdateManager
53128 getUpdateManager : function(){
53129 return this.el.getUpdateManager();
53132 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53133 * @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:
53136 url: "your-url.php",
53137 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53138 callback: yourFunction,
53139 scope: yourObject, //(optional scope)
53142 text: "Loading...",
53147 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53148 * 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.
53149 * @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}
53150 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53151 * @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.
53152 * @return {Roo.ContentPanel} this
53155 var um = this.el.getUpdateManager();
53156 um.update.apply(um, arguments);
53162 * 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.
53163 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53164 * @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)
53165 * @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)
53166 * @return {Roo.UpdateManager} The UpdateManager
53168 setUrl : function(url, params, loadOnce){
53169 if(this.refreshDelegate){
53170 this.removeListener("activate", this.refreshDelegate);
53172 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53173 this.on("activate", this.refreshDelegate);
53174 return this.el.getUpdateManager();
53177 _handleRefresh : function(url, params, loadOnce){
53178 if(!loadOnce || !this.loaded){
53179 var updater = this.el.getUpdateManager();
53180 updater.update(url, params, this._setLoaded.createDelegate(this));
53184 _setLoaded : function(){
53185 this.loaded = true;
53189 * Returns this panel's id
53192 getId : function(){
53197 * Returns this panel's element - used by regiosn to add.
53198 * @return {Roo.Element}
53200 getEl : function(){
53201 return this.wrapEl || this.el;
53204 adjustForComponents : function(width, height)
53206 //Roo.log('adjustForComponents ');
53207 if(this.resizeEl != this.el){
53208 width -= this.el.getFrameWidth('lr');
53209 height -= this.el.getFrameWidth('tb');
53212 var te = this.toolbar.getEl();
53213 height -= te.getHeight();
53214 te.setWidth(width);
53217 var te = this.footer.getEl();
53218 Roo.log("footer:" + te.getHeight());
53220 height -= te.getHeight();
53221 te.setWidth(width);
53225 if(this.adjustments){
53226 width += this.adjustments[0];
53227 height += this.adjustments[1];
53229 return {"width": width, "height": height};
53232 setSize : function(width, height){
53233 if(this.fitToFrame && !this.ignoreResize(width, height)){
53234 if(this.fitContainer && this.resizeEl != this.el){
53235 this.el.setSize(width, height);
53237 var size = this.adjustForComponents(width, height);
53238 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53239 this.fireEvent('resize', this, size.width, size.height);
53244 * Returns this panel's title
53247 getTitle : function(){
53252 * Set this panel's title
53253 * @param {String} title
53255 setTitle : function(title){
53256 this.title = title;
53258 this.region.updatePanelTitle(this, title);
53263 * Returns true is this panel was configured to be closable
53264 * @return {Boolean}
53266 isClosable : function(){
53267 return this.closable;
53270 beforeSlide : function(){
53272 this.resizeEl.clip();
53275 afterSlide : function(){
53277 this.resizeEl.unclip();
53281 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53282 * Will fail silently if the {@link #setUrl} method has not been called.
53283 * This does not activate the panel, just updates its content.
53285 refresh : function(){
53286 if(this.refreshDelegate){
53287 this.loaded = false;
53288 this.refreshDelegate();
53293 * Destroys this panel
53295 destroy : function(){
53296 this.el.removeAllListeners();
53297 var tempEl = document.createElement("span");
53298 tempEl.appendChild(this.el.dom);
53299 tempEl.innerHTML = "";
53305 * form - if the content panel contains a form - this is a reference to it.
53306 * @type {Roo.form.Form}
53310 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53311 * This contains a reference to it.
53317 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53327 * @param {Object} cfg Xtype definition of item to add.
53330 addxtype : function(cfg) {
53332 if (cfg.xtype.match(/^Form$/)) {
53335 //if (this.footer) {
53336 // el = this.footer.container.insertSibling(false, 'before');
53338 el = this.el.createChild();
53341 this.form = new Roo.form.Form(cfg);
53344 if ( this.form.allItems.length) {
53345 this.form.render(el.dom);
53349 // should only have one of theses..
53350 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53351 // views.. should not be just added - used named prop 'view''
53353 cfg.el = this.el.appendChild(document.createElement("div"));
53356 var ret = new Roo.factory(cfg);
53358 ret.render && ret.render(false, ''); // render blank..
53367 * @class Roo.GridPanel
53368 * @extends Roo.ContentPanel
53370 * Create a new GridPanel.
53371 * @param {Roo.grid.Grid} grid The grid for this panel
53372 * @param {String/Object} config A string to set only the panel's title, or a config object
53374 Roo.GridPanel = function(grid, config){
53377 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53378 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53380 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53382 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53385 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53387 // xtype created footer. - not sure if will work as we normally have to render first..
53388 if (this.footer && !this.footer.el && this.footer.xtype) {
53390 this.footer.container = this.grid.getView().getFooterPanel(true);
53391 this.footer.dataSource = this.grid.dataSource;
53392 this.footer = Roo.factory(this.footer, Roo);
53396 grid.monitorWindowResize = false; // turn off autosizing
53397 grid.autoHeight = false;
53398 grid.autoWidth = false;
53400 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53403 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53404 getId : function(){
53405 return this.grid.id;
53409 * Returns the grid for this panel
53410 * @return {Roo.grid.Grid}
53412 getGrid : function(){
53416 setSize : function(width, height){
53417 if(!this.ignoreResize(width, height)){
53418 var grid = this.grid;
53419 var size = this.adjustForComponents(width, height);
53420 grid.getGridEl().setSize(size.width, size.height);
53425 beforeSlide : function(){
53426 this.grid.getView().scroller.clip();
53429 afterSlide : function(){
53430 this.grid.getView().scroller.unclip();
53433 destroy : function(){
53434 this.grid.destroy();
53436 Roo.GridPanel.superclass.destroy.call(this);
53442 * @class Roo.NestedLayoutPanel
53443 * @extends Roo.ContentPanel
53445 * Create a new NestedLayoutPanel.
53448 * @param {Roo.BorderLayout} layout The layout for this panel
53449 * @param {String/Object} config A string to set only the title or a config object
53451 Roo.NestedLayoutPanel = function(layout, config)
53453 // construct with only one argument..
53454 /* FIXME - implement nicer consturctors
53455 if (layout.layout) {
53457 layout = config.layout;
53458 delete config.layout;
53460 if (layout.xtype && !layout.getEl) {
53461 // then layout needs constructing..
53462 layout = Roo.factory(layout, Roo);
53467 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53469 layout.monitorWindowResize = false; // turn off autosizing
53470 this.layout = layout;
53471 this.layout.getEl().addClass("x-layout-nested-layout");
53478 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53480 setSize : function(width, height){
53481 if(!this.ignoreResize(width, height)){
53482 var size = this.adjustForComponents(width, height);
53483 var el = this.layout.getEl();
53484 el.setSize(size.width, size.height);
53485 var touch = el.dom.offsetWidth;
53486 this.layout.layout();
53487 // ie requires a double layout on the first pass
53488 if(Roo.isIE && !this.initialized){
53489 this.initialized = true;
53490 this.layout.layout();
53495 // activate all subpanels if not currently active..
53497 setActiveState : function(active){
53498 this.active = active;
53500 this.fireEvent("deactivate", this);
53504 this.fireEvent("activate", this);
53505 // not sure if this should happen before or after..
53506 if (!this.layout) {
53507 return; // should not happen..
53510 for (var r in this.layout.regions) {
53511 reg = this.layout.getRegion(r);
53512 if (reg.getActivePanel()) {
53513 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53514 reg.setActivePanel(reg.getActivePanel());
53517 if (!reg.panels.length) {
53520 reg.showPanel(reg.getPanel(0));
53529 * Returns the nested BorderLayout for this panel
53530 * @return {Roo.BorderLayout}
53532 getLayout : function(){
53533 return this.layout;
53537 * Adds a xtype elements to the layout of the nested panel
53541 xtype : 'ContentPanel',
53548 xtype : 'NestedLayoutPanel',
53554 items : [ ... list of content panels or nested layout panels.. ]
53558 * @param {Object} cfg Xtype definition of item to add.
53560 addxtype : function(cfg) {
53561 return this.layout.addxtype(cfg);
53566 Roo.ScrollPanel = function(el, config, content){
53567 config = config || {};
53568 config.fitToFrame = true;
53569 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53571 this.el.dom.style.overflow = "hidden";
53572 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53573 this.el.removeClass("x-layout-inactive-content");
53574 this.el.on("mousewheel", this.onWheel, this);
53576 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53577 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53578 up.unselectable(); down.unselectable();
53579 up.on("click", this.scrollUp, this);
53580 down.on("click", this.scrollDown, this);
53581 up.addClassOnOver("x-scroller-btn-over");
53582 down.addClassOnOver("x-scroller-btn-over");
53583 up.addClassOnClick("x-scroller-btn-click");
53584 down.addClassOnClick("x-scroller-btn-click");
53585 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53587 this.resizeEl = this.el;
53588 this.el = wrap; this.up = up; this.down = down;
53591 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53593 wheelIncrement : 5,
53594 scrollUp : function(){
53595 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53598 scrollDown : function(){
53599 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53602 afterScroll : function(){
53603 var el = this.resizeEl;
53604 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53605 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53606 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53609 setSize : function(){
53610 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53611 this.afterScroll();
53614 onWheel : function(e){
53615 var d = e.getWheelDelta();
53616 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53617 this.afterScroll();
53621 setContent : function(content, loadScripts){
53622 this.resizeEl.update(content, loadScripts);
53636 * @class Roo.TreePanel
53637 * @extends Roo.ContentPanel
53639 * Create a new TreePanel. - defaults to fit/scoll contents.
53640 * @param {String/Object} config A string to set only the panel's title, or a config object
53641 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53643 Roo.TreePanel = function(config){
53644 var el = config.el;
53645 var tree = config.tree;
53646 delete config.tree;
53647 delete config.el; // hopefull!
53649 // wrapper for IE7 strict & safari scroll issue
53651 var treeEl = el.createChild();
53652 config.resizeEl = treeEl;
53656 Roo.TreePanel.superclass.constructor.call(this, el, config);
53659 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53660 //console.log(tree);
53661 this.on('activate', function()
53663 if (this.tree.rendered) {
53666 //console.log('render tree');
53667 this.tree.render();
53669 // this should not be needed.. - it's actually the 'el' that resizes?
53670 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53672 //this.on('resize', function (cp, w, h) {
53673 // this.tree.innerCt.setWidth(w);
53674 // this.tree.innerCt.setHeight(h);
53675 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53682 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53699 * Ext JS Library 1.1.1
53700 * Copyright(c) 2006-2007, Ext JS, LLC.
53702 * Originally Released Under LGPL - original licence link has changed is not relivant.
53705 * <script type="text/javascript">
53710 * @class Roo.ReaderLayout
53711 * @extends Roo.BorderLayout
53712 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53713 * center region containing two nested regions (a top one for a list view and one for item preview below),
53714 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53715 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53716 * expedites the setup of the overall layout and regions for this common application style.
53719 var reader = new Roo.ReaderLayout();
53720 var CP = Roo.ContentPanel; // shortcut for adding
53722 reader.beginUpdate();
53723 reader.add("north", new CP("north", "North"));
53724 reader.add("west", new CP("west", {title: "West"}));
53725 reader.add("east", new CP("east", {title: "East"}));
53727 reader.regions.listView.add(new CP("listView", "List"));
53728 reader.regions.preview.add(new CP("preview", "Preview"));
53729 reader.endUpdate();
53732 * Create a new ReaderLayout
53733 * @param {Object} config Configuration options
53734 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53735 * document.body if omitted)
53737 Roo.ReaderLayout = function(config, renderTo){
53738 var c = config || {size:{}};
53739 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53740 north: c.north !== false ? Roo.apply({
53744 }, c.north) : false,
53745 west: c.west !== false ? Roo.apply({
53753 margins:{left:5,right:0,bottom:5,top:5},
53754 cmargins:{left:5,right:5,bottom:5,top:5}
53755 }, c.west) : false,
53756 east: c.east !== false ? Roo.apply({
53764 margins:{left:0,right:5,bottom:5,top:5},
53765 cmargins:{left:5,right:5,bottom:5,top:5}
53766 }, c.east) : false,
53767 center: Roo.apply({
53768 tabPosition: 'top',
53772 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53776 this.el.addClass('x-reader');
53778 this.beginUpdate();
53780 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53781 south: c.preview !== false ? Roo.apply({
53788 cmargins:{top:5,left:0, right:0, bottom:0}
53789 }, c.preview) : false,
53790 center: Roo.apply({
53796 this.add('center', new Roo.NestedLayoutPanel(inner,
53797 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53801 this.regions.preview = inner.getRegion('south');
53802 this.regions.listView = inner.getRegion('center');
53805 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53807 * Ext JS Library 1.1.1
53808 * Copyright(c) 2006-2007, Ext JS, LLC.
53810 * Originally Released Under LGPL - original licence link has changed is not relivant.
53813 * <script type="text/javascript">
53817 * @class Roo.grid.Grid
53818 * @extends Roo.util.Observable
53819 * This class represents the primary interface of a component based grid control.
53820 * <br><br>Usage:<pre><code>
53821 var grid = new Roo.grid.Grid("my-container-id", {
53824 selModel: mySelectionModel,
53825 autoSizeColumns: true,
53826 monitorWindowResize: false,
53827 trackMouseOver: true
53832 * <b>Common Problems:</b><br/>
53833 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53834 * element will correct this<br/>
53835 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53836 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53837 * are unpredictable.<br/>
53838 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53839 * grid to calculate dimensions/offsets.<br/>
53841 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53842 * The container MUST have some type of size defined for the grid to fill. The container will be
53843 * automatically set to position relative if it isn't already.
53844 * @param {Object} config A config object that sets properties on this grid.
53846 Roo.grid.Grid = function(container, config){
53847 // initialize the container
53848 this.container = Roo.get(container);
53849 this.container.update("");
53850 this.container.setStyle("overflow", "hidden");
53851 this.container.addClass('x-grid-container');
53853 this.id = this.container.id;
53855 Roo.apply(this, config);
53856 // check and correct shorthanded configs
53858 this.dataSource = this.ds;
53862 this.colModel = this.cm;
53866 this.selModel = this.sm;
53870 if (this.selModel) {
53871 this.selModel = Roo.factory(this.selModel, Roo.grid);
53872 this.sm = this.selModel;
53873 this.sm.xmodule = this.xmodule || false;
53875 if (typeof(this.colModel.config) == 'undefined') {
53876 this.colModel = new Roo.grid.ColumnModel(this.colModel);
53877 this.cm = this.colModel;
53878 this.cm.xmodule = this.xmodule || false;
53880 if (this.dataSource) {
53881 this.dataSource= Roo.factory(this.dataSource, Roo.data);
53882 this.ds = this.dataSource;
53883 this.ds.xmodule = this.xmodule || false;
53890 this.container.setWidth(this.width);
53894 this.container.setHeight(this.height);
53901 * The raw click event for the entire grid.
53902 * @param {Roo.EventObject} e
53907 * The raw dblclick event for the entire grid.
53908 * @param {Roo.EventObject} e
53912 * @event contextmenu
53913 * The raw contextmenu event for the entire grid.
53914 * @param {Roo.EventObject} e
53916 "contextmenu" : true,
53919 * The raw mousedown event for the entire grid.
53920 * @param {Roo.EventObject} e
53922 "mousedown" : true,
53925 * The raw mouseup event for the entire grid.
53926 * @param {Roo.EventObject} e
53931 * The raw mouseover event for the entire grid.
53932 * @param {Roo.EventObject} e
53934 "mouseover" : true,
53937 * The raw mouseout event for the entire grid.
53938 * @param {Roo.EventObject} e
53943 * The raw keypress event for the entire grid.
53944 * @param {Roo.EventObject} e
53949 * The raw keydown event for the entire grid.
53950 * @param {Roo.EventObject} e
53958 * Fires when a cell is clicked
53959 * @param {Grid} this
53960 * @param {Number} rowIndex
53961 * @param {Number} columnIndex
53962 * @param {Roo.EventObject} e
53964 "cellclick" : true,
53966 * @event celldblclick
53967 * Fires when a cell is double clicked
53968 * @param {Grid} this
53969 * @param {Number} rowIndex
53970 * @param {Number} columnIndex
53971 * @param {Roo.EventObject} e
53973 "celldblclick" : true,
53976 * Fires when a row is clicked
53977 * @param {Grid} this
53978 * @param {Number} rowIndex
53979 * @param {Roo.EventObject} e
53983 * @event rowdblclick
53984 * Fires when a row is double clicked
53985 * @param {Grid} this
53986 * @param {Number} rowIndex
53987 * @param {Roo.EventObject} e
53989 "rowdblclick" : true,
53991 * @event headerclick
53992 * Fires when a header is clicked
53993 * @param {Grid} this
53994 * @param {Number} columnIndex
53995 * @param {Roo.EventObject} e
53997 "headerclick" : true,
53999 * @event headerdblclick
54000 * Fires when a header cell is double clicked
54001 * @param {Grid} this
54002 * @param {Number} columnIndex
54003 * @param {Roo.EventObject} e
54005 "headerdblclick" : true,
54007 * @event rowcontextmenu
54008 * Fires when a row is right clicked
54009 * @param {Grid} this
54010 * @param {Number} rowIndex
54011 * @param {Roo.EventObject} e
54013 "rowcontextmenu" : true,
54015 * @event cellcontextmenu
54016 * Fires when a cell is right clicked
54017 * @param {Grid} this
54018 * @param {Number} rowIndex
54019 * @param {Number} cellIndex
54020 * @param {Roo.EventObject} e
54022 "cellcontextmenu" : true,
54024 * @event headercontextmenu
54025 * Fires when a header is right clicked
54026 * @param {Grid} this
54027 * @param {Number} columnIndex
54028 * @param {Roo.EventObject} e
54030 "headercontextmenu" : true,
54032 * @event bodyscroll
54033 * Fires when the body element is scrolled
54034 * @param {Number} scrollLeft
54035 * @param {Number} scrollTop
54037 "bodyscroll" : true,
54039 * @event columnresize
54040 * Fires when the user resizes a column
54041 * @param {Number} columnIndex
54042 * @param {Number} newSize
54044 "columnresize" : true,
54046 * @event columnmove
54047 * Fires when the user moves a column
54048 * @param {Number} oldIndex
54049 * @param {Number} newIndex
54051 "columnmove" : true,
54054 * Fires when row(s) start being dragged
54055 * @param {Grid} this
54056 * @param {Roo.GridDD} dd The drag drop object
54057 * @param {event} e The raw browser event
54059 "startdrag" : true,
54062 * Fires when a drag operation is complete
54063 * @param {Grid} this
54064 * @param {Roo.GridDD} dd The drag drop object
54065 * @param {event} e The raw browser event
54070 * Fires when dragged row(s) are dropped on a valid DD target
54071 * @param {Grid} this
54072 * @param {Roo.GridDD} dd The drag drop object
54073 * @param {String} targetId The target drag drop object
54074 * @param {event} e The raw browser event
54079 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54080 * @param {Grid} this
54081 * @param {Roo.GridDD} dd The drag drop object
54082 * @param {String} targetId The target drag drop object
54083 * @param {event} e The raw browser event
54088 * Fires when the dragged row(s) first cross another DD target while being dragged
54089 * @param {Grid} this
54090 * @param {Roo.GridDD} dd The drag drop object
54091 * @param {String} targetId The target drag drop object
54092 * @param {event} e The raw browser event
54094 "dragenter" : true,
54097 * Fires when the dragged row(s) leave another DD target while being dragged
54098 * @param {Grid} this
54099 * @param {Roo.GridDD} dd The drag drop object
54100 * @param {String} targetId The target drag drop object
54101 * @param {event} e The raw browser event
54106 * Fires when a row is rendered, so you can change add a style to it.
54107 * @param {GridView} gridview The grid view
54108 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54114 * Fires when the grid is rendered
54115 * @param {Grid} grid
54120 Roo.grid.Grid.superclass.constructor.call(this);
54122 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54125 * @cfg {String} ddGroup - drag drop group.
54129 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54131 minColumnWidth : 25,
54134 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54135 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54136 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54138 autoSizeColumns : false,
54141 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54143 autoSizeHeaders : true,
54146 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54148 monitorWindowResize : true,
54151 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54152 * rows measured to get a columns size. Default is 0 (all rows).
54154 maxRowsToMeasure : 0,
54157 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54159 trackMouseOver : true,
54162 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54166 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54168 enableDragDrop : false,
54171 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54173 enableColumnMove : true,
54176 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54178 enableColumnHide : true,
54181 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54183 enableRowHeightSync : false,
54186 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54191 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54193 autoHeight : false,
54196 * @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.
54198 autoExpandColumn : false,
54201 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54204 autoExpandMin : 50,
54207 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54209 autoExpandMax : 1000,
54212 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54217 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54221 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54231 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54232 * of a fixed width. Default is false.
54235 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54238 * Called once after all setup has been completed and the grid is ready to be rendered.
54239 * @return {Roo.grid.Grid} this
54241 render : function()
54243 var c = this.container;
54244 // try to detect autoHeight/width mode
54245 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54246 this.autoHeight = true;
54248 var view = this.getView();
54251 c.on("click", this.onClick, this);
54252 c.on("dblclick", this.onDblClick, this);
54253 c.on("contextmenu", this.onContextMenu, this);
54254 c.on("keydown", this.onKeyDown, this);
54256 c.on("touchstart", this.onTouchStart, this);
54259 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54261 this.getSelectionModel().init(this);
54266 this.loadMask = new Roo.LoadMask(this.container,
54267 Roo.apply({store:this.dataSource}, this.loadMask));
54271 if (this.toolbar && this.toolbar.xtype) {
54272 this.toolbar.container = this.getView().getHeaderPanel(true);
54273 this.toolbar = new Roo.Toolbar(this.toolbar);
54275 if (this.footer && this.footer.xtype) {
54276 this.footer.dataSource = this.getDataSource();
54277 this.footer.container = this.getView().getFooterPanel(true);
54278 this.footer = Roo.factory(this.footer, Roo);
54280 if (this.dropTarget && this.dropTarget.xtype) {
54281 delete this.dropTarget.xtype;
54282 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54286 this.rendered = true;
54287 this.fireEvent('render', this);
54292 * Reconfigures the grid to use a different Store and Column Model.
54293 * The View will be bound to the new objects and refreshed.
54294 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54295 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54297 reconfigure : function(dataSource, colModel){
54299 this.loadMask.destroy();
54300 this.loadMask = new Roo.LoadMask(this.container,
54301 Roo.apply({store:dataSource}, this.loadMask));
54303 this.view.bind(dataSource, colModel);
54304 this.dataSource = dataSource;
54305 this.colModel = colModel;
54306 this.view.refresh(true);
54310 onKeyDown : function(e){
54311 this.fireEvent("keydown", e);
54315 * Destroy this grid.
54316 * @param {Boolean} removeEl True to remove the element
54318 destroy : function(removeEl, keepListeners){
54320 this.loadMask.destroy();
54322 var c = this.container;
54323 c.removeAllListeners();
54324 this.view.destroy();
54325 this.colModel.purgeListeners();
54326 if(!keepListeners){
54327 this.purgeListeners();
54330 if(removeEl === true){
54336 processEvent : function(name, e){
54337 // does this fire select???
54338 //Roo.log('grid:processEvent ' + name);
54340 if (name != 'touchstart' ) {
54341 this.fireEvent(name, e);
54344 var t = e.getTarget();
54346 var header = v.findHeaderIndex(t);
54347 if(header !== false){
54348 var ename = name == 'touchstart' ? 'click' : name;
54350 this.fireEvent("header" + ename, this, header, e);
54352 var row = v.findRowIndex(t);
54353 var cell = v.findCellIndex(t);
54354 if (name == 'touchstart') {
54355 // first touch is always a click.
54356 // hopefull this happens after selection is updated.?
54359 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54360 var cs = this.selModel.getSelectedCell();
54361 if (row == cs[0] && cell == cs[1]){
54365 if (typeof(this.selModel.getSelections) != 'undefined') {
54366 var cs = this.selModel.getSelections();
54367 var ds = this.dataSource;
54368 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54379 this.fireEvent("row" + name, this, row, e);
54380 if(cell !== false){
54381 this.fireEvent("cell" + name, this, row, cell, e);
54388 onClick : function(e){
54389 this.processEvent("click", e);
54392 onTouchStart : function(e){
54393 this.processEvent("touchstart", e);
54397 onContextMenu : function(e, t){
54398 this.processEvent("contextmenu", e);
54402 onDblClick : function(e){
54403 this.processEvent("dblclick", e);
54407 walkCells : function(row, col, step, fn, scope){
54408 var cm = this.colModel, clen = cm.getColumnCount();
54409 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54421 if(fn.call(scope || this, row, col, cm) === true){
54439 if(fn.call(scope || this, row, col, cm) === true){
54451 getSelections : function(){
54452 return this.selModel.getSelections();
54456 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54457 * but if manual update is required this method will initiate it.
54459 autoSize : function(){
54461 this.view.layout();
54462 if(this.view.adjustForScroll){
54463 this.view.adjustForScroll();
54469 * Returns the grid's underlying element.
54470 * @return {Element} The element
54472 getGridEl : function(){
54473 return this.container;
54476 // private for compatibility, overridden by editor grid
54477 stopEditing : function(){},
54480 * Returns the grid's SelectionModel.
54481 * @return {SelectionModel}
54483 getSelectionModel : function(){
54484 if(!this.selModel){
54485 this.selModel = new Roo.grid.RowSelectionModel();
54487 return this.selModel;
54491 * Returns the grid's DataSource.
54492 * @return {DataSource}
54494 getDataSource : function(){
54495 return this.dataSource;
54499 * Returns the grid's ColumnModel.
54500 * @return {ColumnModel}
54502 getColumnModel : function(){
54503 return this.colModel;
54507 * Returns the grid's GridView object.
54508 * @return {GridView}
54510 getView : function(){
54512 this.view = new Roo.grid.GridView(this.viewConfig);
54517 * Called to get grid's drag proxy text, by default returns this.ddText.
54520 getDragDropText : function(){
54521 var count = this.selModel.getCount();
54522 return String.format(this.ddText, count, count == 1 ? '' : 's');
54526 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54527 * %0 is replaced with the number of selected rows.
54530 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54532 * Ext JS Library 1.1.1
54533 * Copyright(c) 2006-2007, Ext JS, LLC.
54535 * Originally Released Under LGPL - original licence link has changed is not relivant.
54538 * <script type="text/javascript">
54541 Roo.grid.AbstractGridView = function(){
54545 "beforerowremoved" : true,
54546 "beforerowsinserted" : true,
54547 "beforerefresh" : true,
54548 "rowremoved" : true,
54549 "rowsinserted" : true,
54550 "rowupdated" : true,
54553 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54556 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54557 rowClass : "x-grid-row",
54558 cellClass : "x-grid-cell",
54559 tdClass : "x-grid-td",
54560 hdClass : "x-grid-hd",
54561 splitClass : "x-grid-hd-split",
54563 init: function(grid){
54565 var cid = this.grid.getGridEl().id;
54566 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54567 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54568 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54569 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54572 getColumnRenderers : function(){
54573 var renderers = [];
54574 var cm = this.grid.colModel;
54575 var colCount = cm.getColumnCount();
54576 for(var i = 0; i < colCount; i++){
54577 renderers[i] = cm.getRenderer(i);
54582 getColumnIds : function(){
54584 var cm = this.grid.colModel;
54585 var colCount = cm.getColumnCount();
54586 for(var i = 0; i < colCount; i++){
54587 ids[i] = cm.getColumnId(i);
54592 getDataIndexes : function(){
54593 if(!this.indexMap){
54594 this.indexMap = this.buildIndexMap();
54596 return this.indexMap.colToData;
54599 getColumnIndexByDataIndex : function(dataIndex){
54600 if(!this.indexMap){
54601 this.indexMap = this.buildIndexMap();
54603 return this.indexMap.dataToCol[dataIndex];
54607 * Set a css style for a column dynamically.
54608 * @param {Number} colIndex The index of the column
54609 * @param {String} name The css property name
54610 * @param {String} value The css value
54612 setCSSStyle : function(colIndex, name, value){
54613 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54614 Roo.util.CSS.updateRule(selector, name, value);
54617 generateRules : function(cm){
54618 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54619 Roo.util.CSS.removeStyleSheet(rulesId);
54620 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54621 var cid = cm.getColumnId(i);
54622 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54623 this.tdSelector, cid, " {\n}\n",
54624 this.hdSelector, cid, " {\n}\n",
54625 this.splitSelector, cid, " {\n}\n");
54627 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54631 * Ext JS Library 1.1.1
54632 * Copyright(c) 2006-2007, Ext JS, LLC.
54634 * Originally Released Under LGPL - original licence link has changed is not relivant.
54637 * <script type="text/javascript">
54641 // This is a support class used internally by the Grid components
54642 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54644 this.view = grid.getView();
54645 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54646 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54648 this.setHandleElId(Roo.id(hd));
54649 this.setOuterHandleElId(Roo.id(hd2));
54651 this.scroll = false;
54653 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54655 getDragData : function(e){
54656 var t = Roo.lib.Event.getTarget(e);
54657 var h = this.view.findHeaderCell(t);
54659 return {ddel: h.firstChild, header:h};
54664 onInitDrag : function(e){
54665 this.view.headersDisabled = true;
54666 var clone = this.dragData.ddel.cloneNode(true);
54667 clone.id = Roo.id();
54668 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54669 this.proxy.update(clone);
54673 afterValidDrop : function(){
54675 setTimeout(function(){
54676 v.headersDisabled = false;
54680 afterInvalidDrop : function(){
54682 setTimeout(function(){
54683 v.headersDisabled = false;
54689 * Ext JS Library 1.1.1
54690 * Copyright(c) 2006-2007, Ext JS, LLC.
54692 * Originally Released Under LGPL - original licence link has changed is not relivant.
54695 * <script type="text/javascript">
54698 // This is a support class used internally by the Grid components
54699 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54701 this.view = grid.getView();
54702 // split the proxies so they don't interfere with mouse events
54703 this.proxyTop = Roo.DomHelper.append(document.body, {
54704 cls:"col-move-top", html:" "
54706 this.proxyBottom = Roo.DomHelper.append(document.body, {
54707 cls:"col-move-bottom", html:" "
54709 this.proxyTop.hide = this.proxyBottom.hide = function(){
54710 this.setLeftTop(-100,-100);
54711 this.setStyle("visibility", "hidden");
54713 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54714 // temporarily disabled
54715 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54716 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54718 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54719 proxyOffsets : [-4, -9],
54720 fly: Roo.Element.fly,
54722 getTargetFromEvent : function(e){
54723 var t = Roo.lib.Event.getTarget(e);
54724 var cindex = this.view.findCellIndex(t);
54725 if(cindex !== false){
54726 return this.view.getHeaderCell(cindex);
54731 nextVisible : function(h){
54732 var v = this.view, cm = this.grid.colModel;
54735 if(!cm.isHidden(v.getCellIndex(h))){
54743 prevVisible : function(h){
54744 var v = this.view, cm = this.grid.colModel;
54747 if(!cm.isHidden(v.getCellIndex(h))){
54755 positionIndicator : function(h, n, e){
54756 var x = Roo.lib.Event.getPageX(e);
54757 var r = Roo.lib.Dom.getRegion(n.firstChild);
54758 var px, pt, py = r.top + this.proxyOffsets[1];
54759 if((r.right - x) <= (r.right-r.left)/2){
54760 px = r.right+this.view.borderWidth;
54766 var oldIndex = this.view.getCellIndex(h);
54767 var newIndex = this.view.getCellIndex(n);
54769 if(this.grid.colModel.isFixed(newIndex)){
54773 var locked = this.grid.colModel.isLocked(newIndex);
54778 if(oldIndex < newIndex){
54781 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54784 px += this.proxyOffsets[0];
54785 this.proxyTop.setLeftTop(px, py);
54786 this.proxyTop.show();
54787 if(!this.bottomOffset){
54788 this.bottomOffset = this.view.mainHd.getHeight();
54790 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54791 this.proxyBottom.show();
54795 onNodeEnter : function(n, dd, e, data){
54796 if(data.header != n){
54797 this.positionIndicator(data.header, n, e);
54801 onNodeOver : function(n, dd, e, data){
54802 var result = false;
54803 if(data.header != n){
54804 result = this.positionIndicator(data.header, n, e);
54807 this.proxyTop.hide();
54808 this.proxyBottom.hide();
54810 return result ? this.dropAllowed : this.dropNotAllowed;
54813 onNodeOut : function(n, dd, e, data){
54814 this.proxyTop.hide();
54815 this.proxyBottom.hide();
54818 onNodeDrop : function(n, dd, e, data){
54819 var h = data.header;
54821 var cm = this.grid.colModel;
54822 var x = Roo.lib.Event.getPageX(e);
54823 var r = Roo.lib.Dom.getRegion(n.firstChild);
54824 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54825 var oldIndex = this.view.getCellIndex(h);
54826 var newIndex = this.view.getCellIndex(n);
54827 var locked = cm.isLocked(newIndex);
54831 if(oldIndex < newIndex){
54834 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54837 cm.setLocked(oldIndex, locked, true);
54838 cm.moveColumn(oldIndex, newIndex);
54839 this.grid.fireEvent("columnmove", oldIndex, newIndex);
54847 * Ext JS Library 1.1.1
54848 * Copyright(c) 2006-2007, Ext JS, LLC.
54850 * Originally Released Under LGPL - original licence link has changed is not relivant.
54853 * <script type="text/javascript">
54857 * @class Roo.grid.GridView
54858 * @extends Roo.util.Observable
54861 * @param {Object} config
54863 Roo.grid.GridView = function(config){
54864 Roo.grid.GridView.superclass.constructor.call(this);
54867 Roo.apply(this, config);
54870 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
54872 unselectable : 'unselectable="on"',
54873 unselectableCls : 'x-unselectable',
54876 rowClass : "x-grid-row",
54878 cellClass : "x-grid-col",
54880 tdClass : "x-grid-td",
54882 hdClass : "x-grid-hd",
54884 splitClass : "x-grid-split",
54886 sortClasses : ["sort-asc", "sort-desc"],
54888 enableMoveAnim : false,
54892 dh : Roo.DomHelper,
54894 fly : Roo.Element.fly,
54896 css : Roo.util.CSS,
54902 scrollIncrement : 22,
54904 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
54906 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
54908 bind : function(ds, cm){
54910 this.ds.un("load", this.onLoad, this);
54911 this.ds.un("datachanged", this.onDataChange, this);
54912 this.ds.un("add", this.onAdd, this);
54913 this.ds.un("remove", this.onRemove, this);
54914 this.ds.un("update", this.onUpdate, this);
54915 this.ds.un("clear", this.onClear, this);
54918 ds.on("load", this.onLoad, this);
54919 ds.on("datachanged", this.onDataChange, this);
54920 ds.on("add", this.onAdd, this);
54921 ds.on("remove", this.onRemove, this);
54922 ds.on("update", this.onUpdate, this);
54923 ds.on("clear", this.onClear, this);
54928 this.cm.un("widthchange", this.onColWidthChange, this);
54929 this.cm.un("headerchange", this.onHeaderChange, this);
54930 this.cm.un("hiddenchange", this.onHiddenChange, this);
54931 this.cm.un("columnmoved", this.onColumnMove, this);
54932 this.cm.un("columnlockchange", this.onColumnLock, this);
54935 this.generateRules(cm);
54936 cm.on("widthchange", this.onColWidthChange, this);
54937 cm.on("headerchange", this.onHeaderChange, this);
54938 cm.on("hiddenchange", this.onHiddenChange, this);
54939 cm.on("columnmoved", this.onColumnMove, this);
54940 cm.on("columnlockchange", this.onColumnLock, this);
54945 init: function(grid){
54946 Roo.grid.GridView.superclass.init.call(this, grid);
54948 this.bind(grid.dataSource, grid.colModel);
54950 grid.on("headerclick", this.handleHeaderClick, this);
54952 if(grid.trackMouseOver){
54953 grid.on("mouseover", this.onRowOver, this);
54954 grid.on("mouseout", this.onRowOut, this);
54956 grid.cancelTextSelection = function(){};
54957 this.gridId = grid.id;
54959 var tpls = this.templates || {};
54962 tpls.master = new Roo.Template(
54963 '<div class="x-grid" hidefocus="true">',
54964 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
54965 '<div class="x-grid-topbar"></div>',
54966 '<div class="x-grid-scroller"><div></div></div>',
54967 '<div class="x-grid-locked">',
54968 '<div class="x-grid-header">{lockedHeader}</div>',
54969 '<div class="x-grid-body">{lockedBody}</div>',
54971 '<div class="x-grid-viewport">',
54972 '<div class="x-grid-header">{header}</div>',
54973 '<div class="x-grid-body">{body}</div>',
54975 '<div class="x-grid-bottombar"></div>',
54977 '<div class="x-grid-resize-proxy"> </div>',
54980 tpls.master.disableformats = true;
54984 tpls.header = new Roo.Template(
54985 '<table border="0" cellspacing="0" cellpadding="0">',
54986 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
54989 tpls.header.disableformats = true;
54991 tpls.header.compile();
54994 tpls.hcell = new Roo.Template(
54995 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
54996 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
54999 tpls.hcell.disableFormats = true;
55001 tpls.hcell.compile();
55004 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55005 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55006 tpls.hsplit.disableFormats = true;
55008 tpls.hsplit.compile();
55011 tpls.body = new Roo.Template(
55012 '<table border="0" cellspacing="0" cellpadding="0">',
55013 "<tbody>{rows}</tbody>",
55016 tpls.body.disableFormats = true;
55018 tpls.body.compile();
55021 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55022 tpls.row.disableFormats = true;
55024 tpls.row.compile();
55027 tpls.cell = new Roo.Template(
55028 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55029 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55030 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55033 tpls.cell.disableFormats = true;
55035 tpls.cell.compile();
55037 this.templates = tpls;
55040 // remap these for backwards compat
55041 onColWidthChange : function(){
55042 this.updateColumns.apply(this, arguments);
55044 onHeaderChange : function(){
55045 this.updateHeaders.apply(this, arguments);
55047 onHiddenChange : function(){
55048 this.handleHiddenChange.apply(this, arguments);
55050 onColumnMove : function(){
55051 this.handleColumnMove.apply(this, arguments);
55053 onColumnLock : function(){
55054 this.handleLockChange.apply(this, arguments);
55057 onDataChange : function(){
55059 this.updateHeaderSortState();
55062 onClear : function(){
55066 onUpdate : function(ds, record){
55067 this.refreshRow(record);
55070 refreshRow : function(record){
55071 var ds = this.ds, index;
55072 if(typeof record == 'number'){
55074 record = ds.getAt(index);
55076 index = ds.indexOf(record);
55078 this.insertRows(ds, index, index, true);
55079 this.onRemove(ds, record, index+1, true);
55080 this.syncRowHeights(index, index);
55082 this.fireEvent("rowupdated", this, index, record);
55085 onAdd : function(ds, records, index){
55086 this.insertRows(ds, index, index + (records.length-1));
55089 onRemove : function(ds, record, index, isUpdate){
55090 if(isUpdate !== true){
55091 this.fireEvent("beforerowremoved", this, index, record);
55093 var bt = this.getBodyTable(), lt = this.getLockedTable();
55094 if(bt.rows[index]){
55095 bt.firstChild.removeChild(bt.rows[index]);
55097 if(lt.rows[index]){
55098 lt.firstChild.removeChild(lt.rows[index]);
55100 if(isUpdate !== true){
55101 this.stripeRows(index);
55102 this.syncRowHeights(index, index);
55104 this.fireEvent("rowremoved", this, index, record);
55108 onLoad : function(){
55109 this.scrollToTop();
55113 * Scrolls the grid to the top
55115 scrollToTop : function(){
55117 this.scroller.dom.scrollTop = 0;
55123 * Gets a panel in the header of the grid that can be used for toolbars etc.
55124 * After modifying the contents of this panel a call to grid.autoSize() may be
55125 * required to register any changes in size.
55126 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55127 * @return Roo.Element
55129 getHeaderPanel : function(doShow){
55131 this.headerPanel.show();
55133 return this.headerPanel;
55137 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55138 * After modifying the contents of this panel a call to grid.autoSize() may be
55139 * required to register any changes in size.
55140 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55141 * @return Roo.Element
55143 getFooterPanel : function(doShow){
55145 this.footerPanel.show();
55147 return this.footerPanel;
55150 initElements : function(){
55151 var E = Roo.Element;
55152 var el = this.grid.getGridEl().dom.firstChild;
55153 var cs = el.childNodes;
55155 this.el = new E(el);
55157 this.focusEl = new E(el.firstChild);
55158 this.focusEl.swallowEvent("click", true);
55160 this.headerPanel = new E(cs[1]);
55161 this.headerPanel.enableDisplayMode("block");
55163 this.scroller = new E(cs[2]);
55164 this.scrollSizer = new E(this.scroller.dom.firstChild);
55166 this.lockedWrap = new E(cs[3]);
55167 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55168 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55170 this.mainWrap = new E(cs[4]);
55171 this.mainHd = new E(this.mainWrap.dom.firstChild);
55172 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55174 this.footerPanel = new E(cs[5]);
55175 this.footerPanel.enableDisplayMode("block");
55177 this.resizeProxy = new E(cs[6]);
55179 this.headerSelector = String.format(
55180 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55181 this.lockedHd.id, this.mainHd.id
55184 this.splitterSelector = String.format(
55185 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55186 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55189 idToCssName : function(s)
55191 return s.replace(/[^a-z0-9]+/ig, '-');
55194 getHeaderCell : function(index){
55195 return Roo.DomQuery.select(this.headerSelector)[index];
55198 getHeaderCellMeasure : function(index){
55199 return this.getHeaderCell(index).firstChild;
55202 getHeaderCellText : function(index){
55203 return this.getHeaderCell(index).firstChild.firstChild;
55206 getLockedTable : function(){
55207 return this.lockedBody.dom.firstChild;
55210 getBodyTable : function(){
55211 return this.mainBody.dom.firstChild;
55214 getLockedRow : function(index){
55215 return this.getLockedTable().rows[index];
55218 getRow : function(index){
55219 return this.getBodyTable().rows[index];
55222 getRowComposite : function(index){
55224 this.rowEl = new Roo.CompositeElementLite();
55226 var els = [], lrow, mrow;
55227 if(lrow = this.getLockedRow(index)){
55230 if(mrow = this.getRow(index)){
55233 this.rowEl.elements = els;
55237 * Gets the 'td' of the cell
55239 * @param {Integer} rowIndex row to select
55240 * @param {Integer} colIndex column to select
55244 getCell : function(rowIndex, colIndex){
55245 var locked = this.cm.getLockedCount();
55247 if(colIndex < locked){
55248 source = this.lockedBody.dom.firstChild;
55250 source = this.mainBody.dom.firstChild;
55251 colIndex -= locked;
55253 return source.rows[rowIndex].childNodes[colIndex];
55256 getCellText : function(rowIndex, colIndex){
55257 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55260 getCellBox : function(cell){
55261 var b = this.fly(cell).getBox();
55262 if(Roo.isOpera){ // opera fails to report the Y
55263 b.y = cell.offsetTop + this.mainBody.getY();
55268 getCellIndex : function(cell){
55269 var id = String(cell.className).match(this.cellRE);
55271 return parseInt(id[1], 10);
55276 findHeaderIndex : function(n){
55277 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55278 return r ? this.getCellIndex(r) : false;
55281 findHeaderCell : function(n){
55282 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55283 return r ? r : false;
55286 findRowIndex : function(n){
55290 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55291 return r ? r.rowIndex : false;
55294 findCellIndex : function(node){
55295 var stop = this.el.dom;
55296 while(node && node != stop){
55297 if(this.findRE.test(node.className)){
55298 return this.getCellIndex(node);
55300 node = node.parentNode;
55305 getColumnId : function(index){
55306 return this.cm.getColumnId(index);
55309 getSplitters : function()
55311 if(this.splitterSelector){
55312 return Roo.DomQuery.select(this.splitterSelector);
55318 getSplitter : function(index){
55319 return this.getSplitters()[index];
55322 onRowOver : function(e, t){
55324 if((row = this.findRowIndex(t)) !== false){
55325 this.getRowComposite(row).addClass("x-grid-row-over");
55329 onRowOut : function(e, t){
55331 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55332 this.getRowComposite(row).removeClass("x-grid-row-over");
55336 renderHeaders : function(){
55338 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55339 var cb = [], lb = [], sb = [], lsb = [], p = {};
55340 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55341 p.cellId = "x-grid-hd-0-" + i;
55342 p.splitId = "x-grid-csplit-0-" + i;
55343 p.id = cm.getColumnId(i);
55344 p.value = cm.getColumnHeader(i) || "";
55345 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55346 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55347 if(!cm.isLocked(i)){
55348 cb[cb.length] = ct.apply(p);
55349 sb[sb.length] = st.apply(p);
55351 lb[lb.length] = ct.apply(p);
55352 lsb[lsb.length] = st.apply(p);
55355 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55356 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55359 updateHeaders : function(){
55360 var html = this.renderHeaders();
55361 this.lockedHd.update(html[0]);
55362 this.mainHd.update(html[1]);
55366 * Focuses the specified row.
55367 * @param {Number} row The row index
55369 focusRow : function(row)
55371 //Roo.log('GridView.focusRow');
55372 var x = this.scroller.dom.scrollLeft;
55373 this.focusCell(row, 0, false);
55374 this.scroller.dom.scrollLeft = x;
55378 * Focuses the specified cell.
55379 * @param {Number} row The row index
55380 * @param {Number} col The column index
55381 * @param {Boolean} hscroll false to disable horizontal scrolling
55383 focusCell : function(row, col, hscroll)
55385 //Roo.log('GridView.focusCell');
55386 var el = this.ensureVisible(row, col, hscroll);
55387 this.focusEl.alignTo(el, "tl-tl");
55389 this.focusEl.focus();
55391 this.focusEl.focus.defer(1, this.focusEl);
55396 * Scrolls the specified cell into view
55397 * @param {Number} row The row index
55398 * @param {Number} col The column index
55399 * @param {Boolean} hscroll false to disable horizontal scrolling
55401 ensureVisible : function(row, col, hscroll)
55403 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55404 //return null; //disable for testing.
55405 if(typeof row != "number"){
55406 row = row.rowIndex;
55408 if(row < 0 && row >= this.ds.getCount()){
55411 col = (col !== undefined ? col : 0);
55412 var cm = this.grid.colModel;
55413 while(cm.isHidden(col)){
55417 var el = this.getCell(row, col);
55421 var c = this.scroller.dom;
55423 var ctop = parseInt(el.offsetTop, 10);
55424 var cleft = parseInt(el.offsetLeft, 10);
55425 var cbot = ctop + el.offsetHeight;
55426 var cright = cleft + el.offsetWidth;
55428 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55429 var stop = parseInt(c.scrollTop, 10);
55430 var sleft = parseInt(c.scrollLeft, 10);
55431 var sbot = stop + ch;
55432 var sright = sleft + c.clientWidth;
55434 Roo.log('GridView.ensureVisible:' +
55436 ' c.clientHeight:' + c.clientHeight +
55437 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55445 c.scrollTop = ctop;
55446 //Roo.log("set scrolltop to ctop DISABLE?");
55447 }else if(cbot > sbot){
55448 //Roo.log("set scrolltop to cbot-ch");
55449 c.scrollTop = cbot-ch;
55452 if(hscroll !== false){
55454 c.scrollLeft = cleft;
55455 }else if(cright > sright){
55456 c.scrollLeft = cright-c.clientWidth;
55463 updateColumns : function(){
55464 this.grid.stopEditing();
55465 var cm = this.grid.colModel, colIds = this.getColumnIds();
55466 //var totalWidth = cm.getTotalWidth();
55468 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55469 //if(cm.isHidden(i)) continue;
55470 var w = cm.getColumnWidth(i);
55471 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55472 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55474 this.updateSplitters();
55477 generateRules : function(cm){
55478 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55479 Roo.util.CSS.removeStyleSheet(rulesId);
55480 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55481 var cid = cm.getColumnId(i);
55483 if(cm.config[i].align){
55484 align = 'text-align:'+cm.config[i].align+';';
55487 if(cm.isHidden(i)){
55488 hidden = 'display:none;';
55490 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55492 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55493 this.hdSelector, cid, " {\n", align, width, "}\n",
55494 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55495 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55497 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55500 updateSplitters : function(){
55501 var cm = this.cm, s = this.getSplitters();
55502 if(s){ // splitters not created yet
55503 var pos = 0, locked = true;
55504 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55505 if(cm.isHidden(i)) {
55508 var w = cm.getColumnWidth(i); // make sure it's a number
55509 if(!cm.isLocked(i) && locked){
55514 s[i].style.left = (pos-this.splitOffset) + "px";
55519 handleHiddenChange : function(colModel, colIndex, hidden){
55521 this.hideColumn(colIndex);
55523 this.unhideColumn(colIndex);
55527 hideColumn : function(colIndex){
55528 var cid = this.getColumnId(colIndex);
55529 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55530 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55532 this.updateHeaders();
55534 this.updateSplitters();
55538 unhideColumn : function(colIndex){
55539 var cid = this.getColumnId(colIndex);
55540 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55541 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55544 this.updateHeaders();
55546 this.updateSplitters();
55550 insertRows : function(dm, firstRow, lastRow, isUpdate){
55551 if(firstRow == 0 && lastRow == dm.getCount()-1){
55555 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55557 var s = this.getScrollState();
55558 var markup = this.renderRows(firstRow, lastRow);
55559 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55560 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55561 this.restoreScroll(s);
55563 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55564 this.syncRowHeights(firstRow, lastRow);
55565 this.stripeRows(firstRow);
55571 bufferRows : function(markup, target, index){
55572 var before = null, trows = target.rows, tbody = target.tBodies[0];
55573 if(index < trows.length){
55574 before = trows[index];
55576 var b = document.createElement("div");
55577 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55578 var rows = b.firstChild.rows;
55579 for(var i = 0, len = rows.length; i < len; i++){
55581 tbody.insertBefore(rows[0], before);
55583 tbody.appendChild(rows[0]);
55590 deleteRows : function(dm, firstRow, lastRow){
55591 if(dm.getRowCount()<1){
55592 this.fireEvent("beforerefresh", this);
55593 this.mainBody.update("");
55594 this.lockedBody.update("");
55595 this.fireEvent("refresh", this);
55597 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55598 var bt = this.getBodyTable();
55599 var tbody = bt.firstChild;
55600 var rows = bt.rows;
55601 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55602 tbody.removeChild(rows[firstRow]);
55604 this.stripeRows(firstRow);
55605 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55609 updateRows : function(dataSource, firstRow, lastRow){
55610 var s = this.getScrollState();
55612 this.restoreScroll(s);
55615 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55619 this.updateHeaderSortState();
55622 getScrollState : function(){
55624 var sb = this.scroller.dom;
55625 return {left: sb.scrollLeft, top: sb.scrollTop};
55628 stripeRows : function(startRow){
55629 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55632 startRow = startRow || 0;
55633 var rows = this.getBodyTable().rows;
55634 var lrows = this.getLockedTable().rows;
55635 var cls = ' x-grid-row-alt ';
55636 for(var i = startRow, len = rows.length; i < len; i++){
55637 var row = rows[i], lrow = lrows[i];
55638 var isAlt = ((i+1) % 2 == 0);
55639 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55640 if(isAlt == hasAlt){
55644 row.className += " x-grid-row-alt";
55646 row.className = row.className.replace("x-grid-row-alt", "");
55649 lrow.className = row.className;
55654 restoreScroll : function(state){
55655 //Roo.log('GridView.restoreScroll');
55656 var sb = this.scroller.dom;
55657 sb.scrollLeft = state.left;
55658 sb.scrollTop = state.top;
55662 syncScroll : function(){
55663 //Roo.log('GridView.syncScroll');
55664 var sb = this.scroller.dom;
55665 var sh = this.mainHd.dom;
55666 var bs = this.mainBody.dom;
55667 var lv = this.lockedBody.dom;
55668 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55669 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55672 handleScroll : function(e){
55674 var sb = this.scroller.dom;
55675 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55679 handleWheel : function(e){
55680 var d = e.getWheelDelta();
55681 this.scroller.dom.scrollTop -= d*22;
55682 // set this here to prevent jumpy scrolling on large tables
55683 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55687 renderRows : function(startRow, endRow){
55688 // pull in all the crap needed to render rows
55689 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55690 var colCount = cm.getColumnCount();
55692 if(ds.getCount() < 1){
55696 // build a map for all the columns
55698 for(var i = 0; i < colCount; i++){
55699 var name = cm.getDataIndex(i);
55701 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55702 renderer : cm.getRenderer(i),
55703 id : cm.getColumnId(i),
55704 locked : cm.isLocked(i),
55705 has_editor : cm.isCellEditable(i)
55709 startRow = startRow || 0;
55710 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55712 // records to render
55713 var rs = ds.getRange(startRow, endRow);
55715 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55718 // As much as I hate to duplicate code, this was branched because FireFox really hates
55719 // [].join("") on strings. The performance difference was substantial enough to
55720 // branch this function
55721 doRender : Roo.isGecko ?
55722 function(cs, rs, ds, startRow, colCount, stripe){
55723 var ts = this.templates, ct = ts.cell, rt = ts.row;
55725 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55727 var hasListener = this.grid.hasListener('rowclass');
55729 for(var j = 0, len = rs.length; j < len; j++){
55730 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55731 for(var i = 0; i < colCount; i++){
55733 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55735 p.css = p.attr = "";
55736 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55737 if(p.value == undefined || p.value === "") {
55738 p.value = " ";
55741 p.css += ' x-grid-editable-cell';
55743 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55744 p.css += ' x-grid-dirty-cell';
55746 var markup = ct.apply(p);
55754 if(stripe && ((rowIndex+1) % 2 == 0)){
55755 alt.push("x-grid-row-alt")
55758 alt.push( " x-grid-dirty-row");
55761 if(this.getRowClass){
55762 alt.push(this.getRowClass(r, rowIndex));
55768 rowIndex : rowIndex,
55771 this.grid.fireEvent('rowclass', this, rowcfg);
55772 alt.push(rowcfg.rowClass);
55774 rp.alt = alt.join(" ");
55775 lbuf+= rt.apply(rp);
55777 buf+= rt.apply(rp);
55779 return [lbuf, buf];
55781 function(cs, rs, ds, startRow, colCount, stripe){
55782 var ts = this.templates, ct = ts.cell, rt = ts.row;
55784 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55785 var hasListener = this.grid.hasListener('rowclass');
55788 for(var j = 0, len = rs.length; j < len; j++){
55789 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55790 for(var i = 0; i < colCount; i++){
55792 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55794 p.css = p.attr = "";
55795 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55796 if(p.value == undefined || p.value === "") {
55797 p.value = " ";
55801 p.css += ' x-grid-editable-cell';
55803 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55804 p.css += ' x-grid-dirty-cell'
55807 var markup = ct.apply(p);
55809 cb[cb.length] = markup;
55811 lcb[lcb.length] = markup;
55815 if(stripe && ((rowIndex+1) % 2 == 0)){
55816 alt.push( "x-grid-row-alt");
55819 alt.push(" x-grid-dirty-row");
55822 if(this.getRowClass){
55823 alt.push( this.getRowClass(r, rowIndex));
55829 rowIndex : rowIndex,
55832 this.grid.fireEvent('rowclass', this, rowcfg);
55833 alt.push(rowcfg.rowClass);
55836 rp.alt = alt.join(" ");
55837 rp.cells = lcb.join("");
55838 lbuf[lbuf.length] = rt.apply(rp);
55839 rp.cells = cb.join("");
55840 buf[buf.length] = rt.apply(rp);
55842 return [lbuf.join(""), buf.join("")];
55845 renderBody : function(){
55846 var markup = this.renderRows();
55847 var bt = this.templates.body;
55848 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
55852 * Refreshes the grid
55853 * @param {Boolean} headersToo
55855 refresh : function(headersToo){
55856 this.fireEvent("beforerefresh", this);
55857 this.grid.stopEditing();
55858 var result = this.renderBody();
55859 this.lockedBody.update(result[0]);
55860 this.mainBody.update(result[1]);
55861 if(headersToo === true){
55862 this.updateHeaders();
55863 this.updateColumns();
55864 this.updateSplitters();
55865 this.updateHeaderSortState();
55867 this.syncRowHeights();
55869 this.fireEvent("refresh", this);
55872 handleColumnMove : function(cm, oldIndex, newIndex){
55873 this.indexMap = null;
55874 var s = this.getScrollState();
55875 this.refresh(true);
55876 this.restoreScroll(s);
55877 this.afterMove(newIndex);
55880 afterMove : function(colIndex){
55881 if(this.enableMoveAnim && Roo.enableFx){
55882 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
55884 // if multisort - fix sortOrder, and reload..
55885 if (this.grid.dataSource.multiSort) {
55886 // the we can call sort again..
55887 var dm = this.grid.dataSource;
55888 var cm = this.grid.colModel;
55890 for(var i = 0; i < cm.config.length; i++ ) {
55892 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
55893 continue; // dont' bother, it's not in sort list or being set.
55896 so.push(cm.config[i].dataIndex);
55899 dm.load(dm.lastOptions);
55906 updateCell : function(dm, rowIndex, dataIndex){
55907 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
55908 if(typeof colIndex == "undefined"){ // not present in grid
55911 var cm = this.grid.colModel;
55912 var cell = this.getCell(rowIndex, colIndex);
55913 var cellText = this.getCellText(rowIndex, colIndex);
55916 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
55917 id : cm.getColumnId(colIndex),
55918 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
55920 var renderer = cm.getRenderer(colIndex);
55921 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
55922 if(typeof val == "undefined" || val === "") {
55925 cellText.innerHTML = val;
55926 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
55927 this.syncRowHeights(rowIndex, rowIndex);
55930 calcColumnWidth : function(colIndex, maxRowsToMeasure){
55932 if(this.grid.autoSizeHeaders){
55933 var h = this.getHeaderCellMeasure(colIndex);
55934 maxWidth = Math.max(maxWidth, h.scrollWidth);
55937 if(this.cm.isLocked(colIndex)){
55938 tb = this.getLockedTable();
55941 tb = this.getBodyTable();
55942 index = colIndex - this.cm.getLockedCount();
55945 var rows = tb.rows;
55946 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
55947 for(var i = 0; i < stopIndex; i++){
55948 var cell = rows[i].childNodes[index].firstChild;
55949 maxWidth = Math.max(maxWidth, cell.scrollWidth);
55952 return maxWidth + /*margin for error in IE*/ 5;
55955 * Autofit a column to its content.
55956 * @param {Number} colIndex
55957 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
55959 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
55960 if(this.cm.isHidden(colIndex)){
55961 return; // can't calc a hidden column
55964 var cid = this.cm.getColumnId(colIndex);
55965 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
55966 if(this.grid.autoSizeHeaders){
55967 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
55970 var newWidth = this.calcColumnWidth(colIndex);
55971 this.cm.setColumnWidth(colIndex,
55972 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
55973 if(!suppressEvent){
55974 this.grid.fireEvent("columnresize", colIndex, newWidth);
55979 * Autofits all columns to their content and then expands to fit any extra space in the grid
55981 autoSizeColumns : function(){
55982 var cm = this.grid.colModel;
55983 var colCount = cm.getColumnCount();
55984 for(var i = 0; i < colCount; i++){
55985 this.autoSizeColumn(i, true, true);
55987 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
55990 this.updateColumns();
55996 * Autofits all columns to the grid's width proportionate with their current size
55997 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
55999 fitColumns : function(reserveScrollSpace){
56000 var cm = this.grid.colModel;
56001 var colCount = cm.getColumnCount();
56005 for (i = 0; i < colCount; i++){
56006 if(!cm.isHidden(i) && !cm.isFixed(i)){
56007 w = cm.getColumnWidth(i);
56013 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56014 if(reserveScrollSpace){
56017 var frac = (avail - cm.getTotalWidth())/width;
56018 while (cols.length){
56021 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56023 this.updateColumns();
56027 onRowSelect : function(rowIndex){
56028 var row = this.getRowComposite(rowIndex);
56029 row.addClass("x-grid-row-selected");
56032 onRowDeselect : function(rowIndex){
56033 var row = this.getRowComposite(rowIndex);
56034 row.removeClass("x-grid-row-selected");
56037 onCellSelect : function(row, col){
56038 var cell = this.getCell(row, col);
56040 Roo.fly(cell).addClass("x-grid-cell-selected");
56044 onCellDeselect : function(row, col){
56045 var cell = this.getCell(row, col);
56047 Roo.fly(cell).removeClass("x-grid-cell-selected");
56051 updateHeaderSortState : function(){
56053 // sort state can be single { field: xxx, direction : yyy}
56054 // or { xxx=>ASC , yyy : DESC ..... }
56057 if (!this.ds.multiSort) {
56058 var state = this.ds.getSortState();
56062 mstate[state.field] = state.direction;
56063 // FIXME... - this is not used here.. but might be elsewhere..
56064 this.sortState = state;
56067 mstate = this.ds.sortToggle;
56069 //remove existing sort classes..
56071 var sc = this.sortClasses;
56072 var hds = this.el.select(this.headerSelector).removeClass(sc);
56074 for(var f in mstate) {
56076 var sortColumn = this.cm.findColumnIndex(f);
56078 if(sortColumn != -1){
56079 var sortDir = mstate[f];
56080 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56089 handleHeaderClick : function(g, index,e){
56091 Roo.log("header click");
56094 // touch events on header are handled by context
56095 this.handleHdCtx(g,index,e);
56100 if(this.headersDisabled){
56103 var dm = g.dataSource, cm = g.colModel;
56104 if(!cm.isSortable(index)){
56109 if (dm.multiSort) {
56110 // update the sortOrder
56112 for(var i = 0; i < cm.config.length; i++ ) {
56114 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56115 continue; // dont' bother, it's not in sort list or being set.
56118 so.push(cm.config[i].dataIndex);
56124 dm.sort(cm.getDataIndex(index));
56128 destroy : function(){
56130 this.colMenu.removeAll();
56131 Roo.menu.MenuMgr.unregister(this.colMenu);
56132 this.colMenu.getEl().remove();
56133 delete this.colMenu;
56136 this.hmenu.removeAll();
56137 Roo.menu.MenuMgr.unregister(this.hmenu);
56138 this.hmenu.getEl().remove();
56141 if(this.grid.enableColumnMove){
56142 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56144 for(var dd in dds){
56145 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56146 var elid = dds[dd].dragElId;
56148 Roo.get(elid).remove();
56149 } else if(dds[dd].config.isTarget){
56150 dds[dd].proxyTop.remove();
56151 dds[dd].proxyBottom.remove();
56154 if(Roo.dd.DDM.locationCache[dd]){
56155 delete Roo.dd.DDM.locationCache[dd];
56158 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56161 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56162 this.bind(null, null);
56163 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56166 handleLockChange : function(){
56167 this.refresh(true);
56170 onDenyColumnLock : function(){
56174 onDenyColumnHide : function(){
56178 handleHdMenuClick : function(item){
56179 var index = this.hdCtxIndex;
56180 var cm = this.cm, ds = this.ds;
56183 ds.sort(cm.getDataIndex(index), "ASC");
56186 ds.sort(cm.getDataIndex(index), "DESC");
56189 var lc = cm.getLockedCount();
56190 if(cm.getColumnCount(true) <= lc+1){
56191 this.onDenyColumnLock();
56195 cm.setLocked(index, true, true);
56196 cm.moveColumn(index, lc);
56197 this.grid.fireEvent("columnmove", index, lc);
56199 cm.setLocked(index, true);
56203 var lc = cm.getLockedCount();
56204 if((lc-1) != index){
56205 cm.setLocked(index, false, true);
56206 cm.moveColumn(index, lc-1);
56207 this.grid.fireEvent("columnmove", index, lc-1);
56209 cm.setLocked(index, false);
56212 case 'wider': // used to expand cols on touch..
56214 var cw = cm.getColumnWidth(index);
56215 cw += (item.id == 'wider' ? 1 : -1) * 50;
56216 cw = Math.max(0, cw);
56217 cw = Math.min(cw,4000);
56218 cm.setColumnWidth(index, cw);
56222 index = cm.getIndexById(item.id.substr(4));
56224 if(item.checked && cm.getColumnCount(true) <= 1){
56225 this.onDenyColumnHide();
56228 cm.setHidden(index, item.checked);
56234 beforeColMenuShow : function(){
56235 var cm = this.cm, colCount = cm.getColumnCount();
56236 this.colMenu.removeAll();
56237 for(var i = 0; i < colCount; i++){
56238 this.colMenu.add(new Roo.menu.CheckItem({
56239 id: "col-"+cm.getColumnId(i),
56240 text: cm.getColumnHeader(i),
56241 checked: !cm.isHidden(i),
56247 handleHdCtx : function(g, index, e){
56249 var hd = this.getHeaderCell(index);
56250 this.hdCtxIndex = index;
56251 var ms = this.hmenu.items, cm = this.cm;
56252 ms.get("asc").setDisabled(!cm.isSortable(index));
56253 ms.get("desc").setDisabled(!cm.isSortable(index));
56254 if(this.grid.enableColLock !== false){
56255 ms.get("lock").setDisabled(cm.isLocked(index));
56256 ms.get("unlock").setDisabled(!cm.isLocked(index));
56258 this.hmenu.show(hd, "tl-bl");
56261 handleHdOver : function(e){
56262 var hd = this.findHeaderCell(e.getTarget());
56263 if(hd && !this.headersDisabled){
56264 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56265 this.fly(hd).addClass("x-grid-hd-over");
56270 handleHdOut : function(e){
56271 var hd = this.findHeaderCell(e.getTarget());
56273 this.fly(hd).removeClass("x-grid-hd-over");
56277 handleSplitDblClick : function(e, t){
56278 var i = this.getCellIndex(t);
56279 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56280 this.autoSizeColumn(i, true);
56285 render : function(){
56288 var colCount = cm.getColumnCount();
56290 if(this.grid.monitorWindowResize === true){
56291 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56293 var header = this.renderHeaders();
56294 var body = this.templates.body.apply({rows:""});
56295 var html = this.templates.master.apply({
56298 lockedHeader: header[0],
56302 //this.updateColumns();
56304 this.grid.getGridEl().dom.innerHTML = html;
56306 this.initElements();
56308 // a kludge to fix the random scolling effect in webkit
56309 this.el.on("scroll", function() {
56310 this.el.dom.scrollTop=0; // hopefully not recursive..
56313 this.scroller.on("scroll", this.handleScroll, this);
56314 this.lockedBody.on("mousewheel", this.handleWheel, this);
56315 this.mainBody.on("mousewheel", this.handleWheel, this);
56317 this.mainHd.on("mouseover", this.handleHdOver, this);
56318 this.mainHd.on("mouseout", this.handleHdOut, this);
56319 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56320 {delegate: "."+this.splitClass});
56322 this.lockedHd.on("mouseover", this.handleHdOver, this);
56323 this.lockedHd.on("mouseout", this.handleHdOut, this);
56324 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56325 {delegate: "."+this.splitClass});
56327 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56328 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56331 this.updateSplitters();
56333 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56334 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56335 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56338 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56339 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56341 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56342 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56344 if(this.grid.enableColLock !== false){
56345 this.hmenu.add('-',
56346 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56347 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56351 this.hmenu.add('-',
56352 {id:"wider", text: this.columnsWiderText},
56353 {id:"narrow", text: this.columnsNarrowText }
56359 if(this.grid.enableColumnHide !== false){
56361 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56362 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56363 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56365 this.hmenu.add('-',
56366 {id:"columns", text: this.columnsText, menu: this.colMenu}
56369 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56371 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56374 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56375 this.dd = new Roo.grid.GridDragZone(this.grid, {
56376 ddGroup : this.grid.ddGroup || 'GridDD'
56382 for(var i = 0; i < colCount; i++){
56383 if(cm.isHidden(i)){
56384 this.hideColumn(i);
56386 if(cm.config[i].align){
56387 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56388 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56392 this.updateHeaderSortState();
56394 this.beforeInitialResize();
56397 // two part rendering gives faster view to the user
56398 this.renderPhase2.defer(1, this);
56401 renderPhase2 : function(){
56402 // render the rows now
56404 if(this.grid.autoSizeColumns){
56405 this.autoSizeColumns();
56409 beforeInitialResize : function(){
56413 onColumnSplitterMoved : function(i, w){
56414 this.userResized = true;
56415 var cm = this.grid.colModel;
56416 cm.setColumnWidth(i, w, true);
56417 var cid = cm.getColumnId(i);
56418 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56419 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56420 this.updateSplitters();
56422 this.grid.fireEvent("columnresize", i, w);
56425 syncRowHeights : function(startIndex, endIndex){
56426 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56427 startIndex = startIndex || 0;
56428 var mrows = this.getBodyTable().rows;
56429 var lrows = this.getLockedTable().rows;
56430 var len = mrows.length-1;
56431 endIndex = Math.min(endIndex || len, len);
56432 for(var i = startIndex; i <= endIndex; i++){
56433 var m = mrows[i], l = lrows[i];
56434 var h = Math.max(m.offsetHeight, l.offsetHeight);
56435 m.style.height = l.style.height = h + "px";
56440 layout : function(initialRender, is2ndPass){
56442 var auto = g.autoHeight;
56443 var scrollOffset = 16;
56444 var c = g.getGridEl(), cm = this.cm,
56445 expandCol = g.autoExpandColumn,
56447 //c.beginMeasure();
56449 if(!c.dom.offsetWidth){ // display:none?
56451 this.lockedWrap.show();
56452 this.mainWrap.show();
56457 var hasLock = this.cm.isLocked(0);
56459 var tbh = this.headerPanel.getHeight();
56460 var bbh = this.footerPanel.getHeight();
56463 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56464 var newHeight = ch + c.getBorderWidth("tb");
56466 newHeight = Math.min(g.maxHeight, newHeight);
56468 c.setHeight(newHeight);
56472 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56475 var s = this.scroller;
56477 var csize = c.getSize(true);
56479 this.el.setSize(csize.width, csize.height);
56481 this.headerPanel.setWidth(csize.width);
56482 this.footerPanel.setWidth(csize.width);
56484 var hdHeight = this.mainHd.getHeight();
56485 var vw = csize.width;
56486 var vh = csize.height - (tbh + bbh);
56490 var bt = this.getBodyTable();
56492 if(cm.getLockedCount() == cm.config.length){
56493 bt = this.getLockedTable();
56496 var ltWidth = hasLock ?
56497 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56499 var scrollHeight = bt.offsetHeight;
56500 var scrollWidth = ltWidth + bt.offsetWidth;
56501 var vscroll = false, hscroll = false;
56503 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56505 var lw = this.lockedWrap, mw = this.mainWrap;
56506 var lb = this.lockedBody, mb = this.mainBody;
56508 setTimeout(function(){
56509 var t = s.dom.offsetTop;
56510 var w = s.dom.clientWidth,
56511 h = s.dom.clientHeight;
56514 lw.setSize(ltWidth, h);
56516 mw.setLeftTop(ltWidth, t);
56517 mw.setSize(w-ltWidth, h);
56519 lb.setHeight(h-hdHeight);
56520 mb.setHeight(h-hdHeight);
56522 if(is2ndPass !== true && !gv.userResized && expandCol){
56523 // high speed resize without full column calculation
56525 var ci = cm.getIndexById(expandCol);
56527 ci = cm.findColumnIndex(expandCol);
56529 ci = Math.max(0, ci); // make sure it's got at least the first col.
56530 var expandId = cm.getColumnId(ci);
56531 var tw = cm.getTotalWidth(false);
56532 var currentWidth = cm.getColumnWidth(ci);
56533 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56534 if(currentWidth != cw){
56535 cm.setColumnWidth(ci, cw, true);
56536 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56537 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56538 gv.updateSplitters();
56539 gv.layout(false, true);
56551 onWindowResize : function(){
56552 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56558 appendFooter : function(parentEl){
56562 sortAscText : "Sort Ascending",
56563 sortDescText : "Sort Descending",
56564 lockText : "Lock Column",
56565 unlockText : "Unlock Column",
56566 columnsText : "Columns",
56568 columnsWiderText : "Wider",
56569 columnsNarrowText : "Thinner"
56573 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56574 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56575 this.proxy.el.addClass('x-grid3-col-dd');
56578 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56579 handleMouseDown : function(e){
56583 callHandleMouseDown : function(e){
56584 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56589 * Ext JS Library 1.1.1
56590 * Copyright(c) 2006-2007, Ext JS, LLC.
56592 * Originally Released Under LGPL - original licence link has changed is not relivant.
56595 * <script type="text/javascript">
56599 // This is a support class used internally by the Grid components
56600 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56602 this.view = grid.getView();
56603 this.proxy = this.view.resizeProxy;
56604 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56605 "gridSplitters" + this.grid.getGridEl().id, {
56606 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56608 this.setHandleElId(Roo.id(hd));
56609 this.setOuterHandleElId(Roo.id(hd2));
56610 this.scroll = false;
56612 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56613 fly: Roo.Element.fly,
56615 b4StartDrag : function(x, y){
56616 this.view.headersDisabled = true;
56617 this.proxy.setHeight(this.view.mainWrap.getHeight());
56618 var w = this.cm.getColumnWidth(this.cellIndex);
56619 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56620 this.resetConstraints();
56621 this.setXConstraint(minw, 1000);
56622 this.setYConstraint(0, 0);
56623 this.minX = x - minw;
56624 this.maxX = x + 1000;
56626 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56630 handleMouseDown : function(e){
56631 ev = Roo.EventObject.setEvent(e);
56632 var t = this.fly(ev.getTarget());
56633 if(t.hasClass("x-grid-split")){
56634 this.cellIndex = this.view.getCellIndex(t.dom);
56635 this.split = t.dom;
56636 this.cm = this.grid.colModel;
56637 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56638 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56643 endDrag : function(e){
56644 this.view.headersDisabled = false;
56645 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56646 var diff = endX - this.startPos;
56647 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56650 autoOffset : function(){
56651 this.setDelta(0,0);
56655 * Ext JS Library 1.1.1
56656 * Copyright(c) 2006-2007, Ext JS, LLC.
56658 * Originally Released Under LGPL - original licence link has changed is not relivant.
56661 * <script type="text/javascript">
56665 // This is a support class used internally by the Grid components
56666 Roo.grid.GridDragZone = function(grid, config){
56667 this.view = grid.getView();
56668 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56669 if(this.view.lockedBody){
56670 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56671 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56673 this.scroll = false;
56675 this.ddel = document.createElement('div');
56676 this.ddel.className = 'x-grid-dd-wrap';
56679 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56680 ddGroup : "GridDD",
56682 getDragData : function(e){
56683 var t = Roo.lib.Event.getTarget(e);
56684 var rowIndex = this.view.findRowIndex(t);
56685 var sm = this.grid.selModel;
56687 //Roo.log(rowIndex);
56689 if (sm.getSelectedCell) {
56690 // cell selection..
56691 if (!sm.getSelectedCell()) {
56694 if (rowIndex != sm.getSelectedCell()[0]) {
56700 if(rowIndex !== false){
56705 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56707 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56710 if (e.hasModifier()){
56711 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56714 Roo.log("getDragData");
56719 rowIndex: rowIndex,
56720 selections:sm.getSelections ? sm.getSelections() : (
56721 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56728 onInitDrag : function(e){
56729 var data = this.dragData;
56730 this.ddel.innerHTML = this.grid.getDragDropText();
56731 this.proxy.update(this.ddel);
56732 // fire start drag?
56735 afterRepair : function(){
56736 this.dragging = false;
56739 getRepairXY : function(e, data){
56743 onEndDrag : function(data, e){
56747 onValidDrop : function(dd, e, id){
56752 beforeInvalidDrop : function(e, id){
56757 * Ext JS Library 1.1.1
56758 * Copyright(c) 2006-2007, Ext JS, LLC.
56760 * Originally Released Under LGPL - original licence link has changed is not relivant.
56763 * <script type="text/javascript">
56768 * @class Roo.grid.ColumnModel
56769 * @extends Roo.util.Observable
56770 * This is the default implementation of a ColumnModel used by the Grid. It defines
56771 * the columns in the grid.
56774 var colModel = new Roo.grid.ColumnModel([
56775 {header: "Ticker", width: 60, sortable: true, locked: true},
56776 {header: "Company Name", width: 150, sortable: true},
56777 {header: "Market Cap.", width: 100, sortable: true},
56778 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56779 {header: "Employees", width: 100, sortable: true, resizable: false}
56784 * The config options listed for this class are options which may appear in each
56785 * individual column definition.
56786 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56788 * @param {Object} config An Array of column config objects. See this class's
56789 * config objects for details.
56791 Roo.grid.ColumnModel = function(config){
56793 * The config passed into the constructor
56795 this.config = config;
56798 // if no id, create one
56799 // if the column does not have a dataIndex mapping,
56800 // map it to the order it is in the config
56801 for(var i = 0, len = config.length; i < len; i++){
56803 if(typeof c.dataIndex == "undefined"){
56806 if(typeof c.renderer == "string"){
56807 c.renderer = Roo.util.Format[c.renderer];
56809 if(typeof c.id == "undefined"){
56812 if(c.editor && c.editor.xtype){
56813 c.editor = Roo.factory(c.editor, Roo.grid);
56815 if(c.editor && c.editor.isFormField){
56816 c.editor = new Roo.grid.GridEditor(c.editor);
56818 this.lookup[c.id] = c;
56822 * The width of columns which have no width specified (defaults to 100)
56825 this.defaultWidth = 100;
56828 * Default sortable of columns which have no sortable specified (defaults to false)
56831 this.defaultSortable = false;
56835 * @event widthchange
56836 * Fires when the width of a column changes.
56837 * @param {ColumnModel} this
56838 * @param {Number} columnIndex The column index
56839 * @param {Number} newWidth The new width
56841 "widthchange": true,
56843 * @event headerchange
56844 * Fires when the text of a header changes.
56845 * @param {ColumnModel} this
56846 * @param {Number} columnIndex The column index
56847 * @param {Number} newText The new header text
56849 "headerchange": true,
56851 * @event hiddenchange
56852 * Fires when a column is hidden or "unhidden".
56853 * @param {ColumnModel} this
56854 * @param {Number} columnIndex The column index
56855 * @param {Boolean} hidden true if hidden, false otherwise
56857 "hiddenchange": true,
56859 * @event columnmoved
56860 * Fires when a column is moved.
56861 * @param {ColumnModel} this
56862 * @param {Number} oldIndex
56863 * @param {Number} newIndex
56865 "columnmoved" : true,
56867 * @event columlockchange
56868 * Fires when a column's locked state is changed
56869 * @param {ColumnModel} this
56870 * @param {Number} colIndex
56871 * @param {Boolean} locked true if locked
56873 "columnlockchange" : true
56875 Roo.grid.ColumnModel.superclass.constructor.call(this);
56877 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
56879 * @cfg {String} header The header text to display in the Grid view.
56882 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
56883 * {@link Roo.data.Record} definition from which to draw the column's value. If not
56884 * specified, the column's index is used as an index into the Record's data Array.
56887 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
56888 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
56891 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
56892 * Defaults to the value of the {@link #defaultSortable} property.
56893 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
56896 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
56899 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
56902 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
56905 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
56908 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
56909 * given the cell's data value. See {@link #setRenderer}. If not specified, the
56910 * default renderer uses the raw data value. If an object is returned (bootstrap only)
56911 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
56914 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
56917 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
56920 * @cfg {String} cursor (Optional)
56923 * @cfg {String} tooltip (Optional)
56926 * @cfg {Number} xs (Optional)
56929 * @cfg {Number} sm (Optional)
56932 * @cfg {Number} md (Optional)
56935 * @cfg {Number} lg (Optional)
56938 * Returns the id of the column at the specified index.
56939 * @param {Number} index The column index
56940 * @return {String} the id
56942 getColumnId : function(index){
56943 return this.config[index].id;
56947 * Returns the column for a specified id.
56948 * @param {String} id The column id
56949 * @return {Object} the column
56951 getColumnById : function(id){
56952 return this.lookup[id];
56957 * Returns the column for a specified dataIndex.
56958 * @param {String} dataIndex The column dataIndex
56959 * @return {Object|Boolean} the column or false if not found
56961 getColumnByDataIndex: function(dataIndex){
56962 var index = this.findColumnIndex(dataIndex);
56963 return index > -1 ? this.config[index] : false;
56967 * Returns the index for a specified column id.
56968 * @param {String} id The column id
56969 * @return {Number} the index, or -1 if not found
56971 getIndexById : function(id){
56972 for(var i = 0, len = this.config.length; i < len; i++){
56973 if(this.config[i].id == id){
56981 * Returns the index for a specified column dataIndex.
56982 * @param {String} dataIndex The column dataIndex
56983 * @return {Number} the index, or -1 if not found
56986 findColumnIndex : function(dataIndex){
56987 for(var i = 0, len = this.config.length; i < len; i++){
56988 if(this.config[i].dataIndex == dataIndex){
56996 moveColumn : function(oldIndex, newIndex){
56997 var c = this.config[oldIndex];
56998 this.config.splice(oldIndex, 1);
56999 this.config.splice(newIndex, 0, c);
57000 this.dataMap = null;
57001 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57004 isLocked : function(colIndex){
57005 return this.config[colIndex].locked === true;
57008 setLocked : function(colIndex, value, suppressEvent){
57009 if(this.isLocked(colIndex) == value){
57012 this.config[colIndex].locked = value;
57013 if(!suppressEvent){
57014 this.fireEvent("columnlockchange", this, colIndex, value);
57018 getTotalLockedWidth : function(){
57019 var totalWidth = 0;
57020 for(var i = 0; i < this.config.length; i++){
57021 if(this.isLocked(i) && !this.isHidden(i)){
57022 this.totalWidth += this.getColumnWidth(i);
57028 getLockedCount : function(){
57029 for(var i = 0, len = this.config.length; i < len; i++){
57030 if(!this.isLocked(i)){
57035 return this.config.length;
57039 * Returns the number of columns.
57042 getColumnCount : function(visibleOnly){
57043 if(visibleOnly === true){
57045 for(var i = 0, len = this.config.length; i < len; i++){
57046 if(!this.isHidden(i)){
57052 return this.config.length;
57056 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57057 * @param {Function} fn
57058 * @param {Object} scope (optional)
57059 * @return {Array} result
57061 getColumnsBy : function(fn, scope){
57063 for(var i = 0, len = this.config.length; i < len; i++){
57064 var c = this.config[i];
57065 if(fn.call(scope||this, c, i) === true){
57073 * Returns true if the specified column is sortable.
57074 * @param {Number} col The column index
57075 * @return {Boolean}
57077 isSortable : function(col){
57078 if(typeof this.config[col].sortable == "undefined"){
57079 return this.defaultSortable;
57081 return this.config[col].sortable;
57085 * Returns the rendering (formatting) function defined for the column.
57086 * @param {Number} col The column index.
57087 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57089 getRenderer : function(col){
57090 if(!this.config[col].renderer){
57091 return Roo.grid.ColumnModel.defaultRenderer;
57093 return this.config[col].renderer;
57097 * Sets the rendering (formatting) function for a column.
57098 * @param {Number} col The column index
57099 * @param {Function} fn The function to use to process the cell's raw data
57100 * to return HTML markup for the grid view. The render function is called with
57101 * the following parameters:<ul>
57102 * <li>Data value.</li>
57103 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57104 * <li>css A CSS style string to apply to the table cell.</li>
57105 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57106 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57107 * <li>Row index</li>
57108 * <li>Column index</li>
57109 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57111 setRenderer : function(col, fn){
57112 this.config[col].renderer = fn;
57116 * Returns the width for the specified column.
57117 * @param {Number} col The column index
57120 getColumnWidth : function(col){
57121 return this.config[col].width * 1 || this.defaultWidth;
57125 * Sets the width for a column.
57126 * @param {Number} col The column index
57127 * @param {Number} width The new width
57129 setColumnWidth : function(col, width, suppressEvent){
57130 this.config[col].width = width;
57131 this.totalWidth = null;
57132 if(!suppressEvent){
57133 this.fireEvent("widthchange", this, col, width);
57138 * Returns the total width of all columns.
57139 * @param {Boolean} includeHidden True to include hidden column widths
57142 getTotalWidth : function(includeHidden){
57143 if(!this.totalWidth){
57144 this.totalWidth = 0;
57145 for(var i = 0, len = this.config.length; i < len; i++){
57146 if(includeHidden || !this.isHidden(i)){
57147 this.totalWidth += this.getColumnWidth(i);
57151 return this.totalWidth;
57155 * Returns the header for the specified column.
57156 * @param {Number} col The column index
57159 getColumnHeader : function(col){
57160 return this.config[col].header;
57164 * Sets the header for a column.
57165 * @param {Number} col The column index
57166 * @param {String} header The new header
57168 setColumnHeader : function(col, header){
57169 this.config[col].header = header;
57170 this.fireEvent("headerchange", this, col, header);
57174 * Returns the tooltip for the specified column.
57175 * @param {Number} col The column index
57178 getColumnTooltip : function(col){
57179 return this.config[col].tooltip;
57182 * Sets the tooltip for a column.
57183 * @param {Number} col The column index
57184 * @param {String} tooltip The new tooltip
57186 setColumnTooltip : function(col, tooltip){
57187 this.config[col].tooltip = tooltip;
57191 * Returns the dataIndex for the specified column.
57192 * @param {Number} col The column index
57195 getDataIndex : function(col){
57196 return this.config[col].dataIndex;
57200 * Sets the dataIndex for a column.
57201 * @param {Number} col The column index
57202 * @param {Number} dataIndex The new dataIndex
57204 setDataIndex : function(col, dataIndex){
57205 this.config[col].dataIndex = dataIndex;
57211 * Returns true if the cell is editable.
57212 * @param {Number} colIndex The column index
57213 * @param {Number} rowIndex The row index - this is nto actually used..?
57214 * @return {Boolean}
57216 isCellEditable : function(colIndex, rowIndex){
57217 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57221 * Returns the editor defined for the cell/column.
57222 * return false or null to disable editing.
57223 * @param {Number} colIndex The column index
57224 * @param {Number} rowIndex The row index
57227 getCellEditor : function(colIndex, rowIndex){
57228 return this.config[colIndex].editor;
57232 * Sets if a column is editable.
57233 * @param {Number} col The column index
57234 * @param {Boolean} editable True if the column is editable
57236 setEditable : function(col, editable){
57237 this.config[col].editable = editable;
57242 * Returns true if the column is hidden.
57243 * @param {Number} colIndex The column index
57244 * @return {Boolean}
57246 isHidden : function(colIndex){
57247 return this.config[colIndex].hidden;
57252 * Returns true if the column width cannot be changed
57254 isFixed : function(colIndex){
57255 return this.config[colIndex].fixed;
57259 * Returns true if the column can be resized
57260 * @return {Boolean}
57262 isResizable : function(colIndex){
57263 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57266 * Sets if a column is hidden.
57267 * @param {Number} colIndex The column index
57268 * @param {Boolean} hidden True if the column is hidden
57270 setHidden : function(colIndex, hidden){
57271 this.config[colIndex].hidden = hidden;
57272 this.totalWidth = null;
57273 this.fireEvent("hiddenchange", this, colIndex, hidden);
57277 * Sets the editor for a column.
57278 * @param {Number} col The column index
57279 * @param {Object} editor The editor object
57281 setEditor : function(col, editor){
57282 this.config[col].editor = editor;
57286 Roo.grid.ColumnModel.defaultRenderer = function(value){
57287 if(typeof value == "string" && value.length < 1){
57293 // Alias for backwards compatibility
57294 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57297 * Ext JS Library 1.1.1
57298 * Copyright(c) 2006-2007, Ext JS, LLC.
57300 * Originally Released Under LGPL - original licence link has changed is not relivant.
57303 * <script type="text/javascript">
57307 * @class Roo.grid.AbstractSelectionModel
57308 * @extends Roo.util.Observable
57309 * Abstract base class for grid SelectionModels. It provides the interface that should be
57310 * implemented by descendant classes. This class should not be directly instantiated.
57313 Roo.grid.AbstractSelectionModel = function(){
57314 this.locked = false;
57315 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57318 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57319 /** @ignore Called by the grid automatically. Do not call directly. */
57320 init : function(grid){
57326 * Locks the selections.
57329 this.locked = true;
57333 * Unlocks the selections.
57335 unlock : function(){
57336 this.locked = false;
57340 * Returns true if the selections are locked.
57341 * @return {Boolean}
57343 isLocked : function(){
57344 return this.locked;
57348 * Ext JS Library 1.1.1
57349 * Copyright(c) 2006-2007, Ext JS, LLC.
57351 * Originally Released Under LGPL - original licence link has changed is not relivant.
57354 * <script type="text/javascript">
57357 * @extends Roo.grid.AbstractSelectionModel
57358 * @class Roo.grid.RowSelectionModel
57359 * The default SelectionModel used by {@link Roo.grid.Grid}.
57360 * It supports multiple selections and keyboard selection/navigation.
57362 * @param {Object} config
57364 Roo.grid.RowSelectionModel = function(config){
57365 Roo.apply(this, config);
57366 this.selections = new Roo.util.MixedCollection(false, function(o){
57371 this.lastActive = false;
57375 * @event selectionchange
57376 * Fires when the selection changes
57377 * @param {SelectionModel} this
57379 "selectionchange" : true,
57381 * @event afterselectionchange
57382 * Fires after the selection changes (eg. by key press or clicking)
57383 * @param {SelectionModel} this
57385 "afterselectionchange" : true,
57387 * @event beforerowselect
57388 * Fires when a row is selected being selected, return false to cancel.
57389 * @param {SelectionModel} this
57390 * @param {Number} rowIndex The selected index
57391 * @param {Boolean} keepExisting False if other selections will be cleared
57393 "beforerowselect" : true,
57396 * Fires when a row is selected.
57397 * @param {SelectionModel} this
57398 * @param {Number} rowIndex The selected index
57399 * @param {Roo.data.Record} r The record
57401 "rowselect" : true,
57403 * @event rowdeselect
57404 * Fires when a row is deselected.
57405 * @param {SelectionModel} this
57406 * @param {Number} rowIndex The selected index
57408 "rowdeselect" : true
57410 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57411 this.locked = false;
57414 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57416 * @cfg {Boolean} singleSelect
57417 * True to allow selection of only one row at a time (defaults to false)
57419 singleSelect : false,
57422 initEvents : function(){
57424 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57425 this.grid.on("mousedown", this.handleMouseDown, this);
57426 }else{ // allow click to work like normal
57427 this.grid.on("rowclick", this.handleDragableRowClick, this);
57430 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57431 "up" : function(e){
57433 this.selectPrevious(e.shiftKey);
57434 }else if(this.last !== false && this.lastActive !== false){
57435 var last = this.last;
57436 this.selectRange(this.last, this.lastActive-1);
57437 this.grid.getView().focusRow(this.lastActive);
57438 if(last !== false){
57442 this.selectFirstRow();
57444 this.fireEvent("afterselectionchange", this);
57446 "down" : function(e){
57448 this.selectNext(e.shiftKey);
57449 }else if(this.last !== false && this.lastActive !== false){
57450 var last = this.last;
57451 this.selectRange(this.last, this.lastActive+1);
57452 this.grid.getView().focusRow(this.lastActive);
57453 if(last !== false){
57457 this.selectFirstRow();
57459 this.fireEvent("afterselectionchange", this);
57464 var view = this.grid.view;
57465 view.on("refresh", this.onRefresh, this);
57466 view.on("rowupdated", this.onRowUpdated, this);
57467 view.on("rowremoved", this.onRemove, this);
57471 onRefresh : function(){
57472 var ds = this.grid.dataSource, i, v = this.grid.view;
57473 var s = this.selections;
57474 s.each(function(r){
57475 if((i = ds.indexOfId(r.id)) != -1){
57477 s.add(ds.getAt(i)); // updating the selection relate data
57485 onRemove : function(v, index, r){
57486 this.selections.remove(r);
57490 onRowUpdated : function(v, index, r){
57491 if(this.isSelected(r)){
57492 v.onRowSelect(index);
57498 * @param {Array} records The records to select
57499 * @param {Boolean} keepExisting (optional) True to keep existing selections
57501 selectRecords : function(records, keepExisting){
57503 this.clearSelections();
57505 var ds = this.grid.dataSource;
57506 for(var i = 0, len = records.length; i < len; i++){
57507 this.selectRow(ds.indexOf(records[i]), true);
57512 * Gets the number of selected rows.
57515 getCount : function(){
57516 return this.selections.length;
57520 * Selects the first row in the grid.
57522 selectFirstRow : function(){
57527 * Select the last row.
57528 * @param {Boolean} keepExisting (optional) True to keep existing selections
57530 selectLastRow : function(keepExisting){
57531 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57535 * Selects the row immediately following the last selected row.
57536 * @param {Boolean} keepExisting (optional) True to keep existing selections
57538 selectNext : function(keepExisting){
57539 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57540 this.selectRow(this.last+1, keepExisting);
57541 this.grid.getView().focusRow(this.last);
57546 * Selects the row that precedes the last selected row.
57547 * @param {Boolean} keepExisting (optional) True to keep existing selections
57549 selectPrevious : function(keepExisting){
57551 this.selectRow(this.last-1, keepExisting);
57552 this.grid.getView().focusRow(this.last);
57557 * Returns the selected records
57558 * @return {Array} Array of selected records
57560 getSelections : function(){
57561 return [].concat(this.selections.items);
57565 * Returns the first selected record.
57568 getSelected : function(){
57569 return this.selections.itemAt(0);
57574 * Clears all selections.
57576 clearSelections : function(fast){
57581 var ds = this.grid.dataSource;
57582 var s = this.selections;
57583 s.each(function(r){
57584 this.deselectRow(ds.indexOfId(r.id));
57588 this.selections.clear();
57595 * Selects all rows.
57597 selectAll : function(){
57601 this.selections.clear();
57602 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57603 this.selectRow(i, true);
57608 * Returns True if there is a selection.
57609 * @return {Boolean}
57611 hasSelection : function(){
57612 return this.selections.length > 0;
57616 * Returns True if the specified row is selected.
57617 * @param {Number/Record} record The record or index of the record to check
57618 * @return {Boolean}
57620 isSelected : function(index){
57621 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57622 return (r && this.selections.key(r.id) ? true : false);
57626 * Returns True if the specified record id is selected.
57627 * @param {String} id The id of record to check
57628 * @return {Boolean}
57630 isIdSelected : function(id){
57631 return (this.selections.key(id) ? true : false);
57635 handleMouseDown : function(e, t){
57636 var view = this.grid.getView(), rowIndex;
57637 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57640 if(e.shiftKey && this.last !== false){
57641 var last = this.last;
57642 this.selectRange(last, rowIndex, e.ctrlKey);
57643 this.last = last; // reset the last
57644 view.focusRow(rowIndex);
57646 var isSelected = this.isSelected(rowIndex);
57647 if(e.button !== 0 && isSelected){
57648 view.focusRow(rowIndex);
57649 }else if(e.ctrlKey && isSelected){
57650 this.deselectRow(rowIndex);
57651 }else if(!isSelected){
57652 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57653 view.focusRow(rowIndex);
57656 this.fireEvent("afterselectionchange", this);
57659 handleDragableRowClick : function(grid, rowIndex, e)
57661 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57662 this.selectRow(rowIndex, false);
57663 grid.view.focusRow(rowIndex);
57664 this.fireEvent("afterselectionchange", this);
57669 * Selects multiple rows.
57670 * @param {Array} rows Array of the indexes of the row to select
57671 * @param {Boolean} keepExisting (optional) True to keep existing selections
57673 selectRows : function(rows, keepExisting){
57675 this.clearSelections();
57677 for(var i = 0, len = rows.length; i < len; i++){
57678 this.selectRow(rows[i], true);
57683 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57684 * @param {Number} startRow The index of the first row in the range
57685 * @param {Number} endRow The index of the last row in the range
57686 * @param {Boolean} keepExisting (optional) True to retain existing selections
57688 selectRange : function(startRow, endRow, keepExisting){
57693 this.clearSelections();
57695 if(startRow <= endRow){
57696 for(var i = startRow; i <= endRow; i++){
57697 this.selectRow(i, true);
57700 for(var i = startRow; i >= endRow; i--){
57701 this.selectRow(i, true);
57707 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57708 * @param {Number} startRow The index of the first row in the range
57709 * @param {Number} endRow The index of the last row in the range
57711 deselectRange : function(startRow, endRow, preventViewNotify){
57715 for(var i = startRow; i <= endRow; i++){
57716 this.deselectRow(i, preventViewNotify);
57722 * @param {Number} row The index of the row to select
57723 * @param {Boolean} keepExisting (optional) True to keep existing selections
57725 selectRow : function(index, keepExisting, preventViewNotify){
57726 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57729 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57730 if(!keepExisting || this.singleSelect){
57731 this.clearSelections();
57733 var r = this.grid.dataSource.getAt(index);
57734 this.selections.add(r);
57735 this.last = this.lastActive = index;
57736 if(!preventViewNotify){
57737 this.grid.getView().onRowSelect(index);
57739 this.fireEvent("rowselect", this, index, r);
57740 this.fireEvent("selectionchange", this);
57746 * @param {Number} row The index of the row to deselect
57748 deselectRow : function(index, preventViewNotify){
57752 if(this.last == index){
57755 if(this.lastActive == index){
57756 this.lastActive = false;
57758 var r = this.grid.dataSource.getAt(index);
57759 this.selections.remove(r);
57760 if(!preventViewNotify){
57761 this.grid.getView().onRowDeselect(index);
57763 this.fireEvent("rowdeselect", this, index);
57764 this.fireEvent("selectionchange", this);
57768 restoreLast : function(){
57770 this.last = this._last;
57775 acceptsNav : function(row, col, cm){
57776 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57780 onEditorKey : function(field, e){
57781 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57786 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57788 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57790 }else if(k == e.ENTER && !e.ctrlKey){
57794 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57796 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57798 }else if(k == e.ESC){
57802 g.startEditing(newCell[0], newCell[1]);
57807 * Ext JS Library 1.1.1
57808 * Copyright(c) 2006-2007, Ext JS, LLC.
57810 * Originally Released Under LGPL - original licence link has changed is not relivant.
57813 * <script type="text/javascript">
57816 * @class Roo.grid.CellSelectionModel
57817 * @extends Roo.grid.AbstractSelectionModel
57818 * This class provides the basic implementation for cell selection in a grid.
57820 * @param {Object} config The object containing the configuration of this model.
57821 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57823 Roo.grid.CellSelectionModel = function(config){
57824 Roo.apply(this, config);
57826 this.selection = null;
57830 * @event beforerowselect
57831 * Fires before a cell is selected.
57832 * @param {SelectionModel} this
57833 * @param {Number} rowIndex The selected row index
57834 * @param {Number} colIndex The selected cell index
57836 "beforecellselect" : true,
57838 * @event cellselect
57839 * Fires when a cell is selected.
57840 * @param {SelectionModel} this
57841 * @param {Number} rowIndex The selected row index
57842 * @param {Number} colIndex The selected cell index
57844 "cellselect" : true,
57846 * @event selectionchange
57847 * Fires when the active selection changes.
57848 * @param {SelectionModel} this
57849 * @param {Object} selection null for no selection or an object (o) with two properties
57851 <li>o.record: the record object for the row the selection is in</li>
57852 <li>o.cell: An array of [rowIndex, columnIndex]</li>
57855 "selectionchange" : true,
57858 * Fires when the tab (or enter) was pressed on the last editable cell
57859 * You can use this to trigger add new row.
57860 * @param {SelectionModel} this
57864 * @event beforeeditnext
57865 * Fires before the next editable sell is made active
57866 * You can use this to skip to another cell or fire the tabend
57867 * if you set cell to false
57868 * @param {Object} eventdata object : { cell : [ row, col ] }
57870 "beforeeditnext" : true
57872 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
57875 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
57877 enter_is_tab: false,
57880 initEvents : function(){
57881 this.grid.on("mousedown", this.handleMouseDown, this);
57882 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
57883 var view = this.grid.view;
57884 view.on("refresh", this.onViewChange, this);
57885 view.on("rowupdated", this.onRowUpdated, this);
57886 view.on("beforerowremoved", this.clearSelections, this);
57887 view.on("beforerowsinserted", this.clearSelections, this);
57888 if(this.grid.isEditor){
57889 this.grid.on("beforeedit", this.beforeEdit, this);
57894 beforeEdit : function(e){
57895 this.select(e.row, e.column, false, true, e.record);
57899 onRowUpdated : function(v, index, r){
57900 if(this.selection && this.selection.record == r){
57901 v.onCellSelect(index, this.selection.cell[1]);
57906 onViewChange : function(){
57907 this.clearSelections(true);
57911 * Returns the currently selected cell,.
57912 * @return {Array} The selected cell (row, column) or null if none selected.
57914 getSelectedCell : function(){
57915 return this.selection ? this.selection.cell : null;
57919 * Clears all selections.
57920 * @param {Boolean} true to prevent the gridview from being notified about the change.
57922 clearSelections : function(preventNotify){
57923 var s = this.selection;
57925 if(preventNotify !== true){
57926 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
57928 this.selection = null;
57929 this.fireEvent("selectionchange", this, null);
57934 * Returns true if there is a selection.
57935 * @return {Boolean}
57937 hasSelection : function(){
57938 return this.selection ? true : false;
57942 handleMouseDown : function(e, t){
57943 var v = this.grid.getView();
57944 if(this.isLocked()){
57947 var row = v.findRowIndex(t);
57948 var cell = v.findCellIndex(t);
57949 if(row !== false && cell !== false){
57950 this.select(row, cell);
57956 * @param {Number} rowIndex
57957 * @param {Number} collIndex
57959 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
57960 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
57961 this.clearSelections();
57962 r = r || this.grid.dataSource.getAt(rowIndex);
57965 cell : [rowIndex, colIndex]
57967 if(!preventViewNotify){
57968 var v = this.grid.getView();
57969 v.onCellSelect(rowIndex, colIndex);
57970 if(preventFocus !== true){
57971 v.focusCell(rowIndex, colIndex);
57974 this.fireEvent("cellselect", this, rowIndex, colIndex);
57975 this.fireEvent("selectionchange", this, this.selection);
57980 isSelectable : function(rowIndex, colIndex, cm){
57981 return !cm.isHidden(colIndex);
57985 handleKeyDown : function(e){
57986 //Roo.log('Cell Sel Model handleKeyDown');
57987 if(!e.isNavKeyPress()){
57990 var g = this.grid, s = this.selection;
57993 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
57995 this.select(cell[0], cell[1]);
58000 var walk = function(row, col, step){
58001 return g.walkCells(row, col, step, sm.isSelectable, sm);
58003 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58010 // handled by onEditorKey
58011 if (g.isEditor && g.editing) {
58015 newCell = walk(r, c-1, -1);
58017 newCell = walk(r, c+1, 1);
58022 newCell = walk(r+1, c, 1);
58026 newCell = walk(r-1, c, -1);
58030 newCell = walk(r, c+1, 1);
58034 newCell = walk(r, c-1, -1);
58039 if(g.isEditor && !g.editing){
58040 g.startEditing(r, c);
58049 this.select(newCell[0], newCell[1]);
58055 acceptsNav : function(row, col, cm){
58056 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58060 * @param {Number} field (not used) - as it's normally used as a listener
58061 * @param {Number} e - event - fake it by using
58063 * var e = Roo.EventObjectImpl.prototype;
58064 * e.keyCode = e.TAB
58068 onEditorKey : function(field, e){
58070 var k = e.getKey(),
58073 ed = g.activeEditor,
58075 ///Roo.log('onEditorKey' + k);
58078 if (this.enter_is_tab && k == e.ENTER) {
58084 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58086 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58092 } else if(k == e.ENTER && !e.ctrlKey){
58095 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58097 } else if(k == e.ESC){
58102 var ecall = { cell : newCell, forward : forward };
58103 this.fireEvent('beforeeditnext', ecall );
58104 newCell = ecall.cell;
58105 forward = ecall.forward;
58109 //Roo.log('next cell after edit');
58110 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58111 } else if (forward) {
58112 // tabbed past last
58113 this.fireEvent.defer(100, this, ['tabend',this]);
58118 * Ext JS Library 1.1.1
58119 * Copyright(c) 2006-2007, Ext JS, LLC.
58121 * Originally Released Under LGPL - original licence link has changed is not relivant.
58124 * <script type="text/javascript">
58128 * @class Roo.grid.EditorGrid
58129 * @extends Roo.grid.Grid
58130 * Class for creating and editable grid.
58131 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58132 * The container MUST have some type of size defined for the grid to fill. The container will be
58133 * automatically set to position relative if it isn't already.
58134 * @param {Object} dataSource The data model to bind to
58135 * @param {Object} colModel The column model with info about this grid's columns
58137 Roo.grid.EditorGrid = function(container, config){
58138 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58139 this.getGridEl().addClass("xedit-grid");
58141 if(!this.selModel){
58142 this.selModel = new Roo.grid.CellSelectionModel();
58145 this.activeEditor = null;
58149 * @event beforeedit
58150 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58151 * <ul style="padding:5px;padding-left:16px;">
58152 * <li>grid - This grid</li>
58153 * <li>record - The record being edited</li>
58154 * <li>field - The field name being edited</li>
58155 * <li>value - The value for the field being edited.</li>
58156 * <li>row - The grid row index</li>
58157 * <li>column - The grid column index</li>
58158 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58160 * @param {Object} e An edit event (see above for description)
58162 "beforeedit" : true,
58165 * Fires after a cell is edited. <br />
58166 * <ul style="padding:5px;padding-left:16px;">
58167 * <li>grid - This grid</li>
58168 * <li>record - The record being edited</li>
58169 * <li>field - The field name being edited</li>
58170 * <li>value - The value being set</li>
58171 * <li>originalValue - The original value for the field, before the edit.</li>
58172 * <li>row - The grid row index</li>
58173 * <li>column - The grid column index</li>
58175 * @param {Object} e An edit event (see above for description)
58177 "afteredit" : true,
58179 * @event validateedit
58180 * Fires after a cell is edited, but before the value is set in the record.
58181 * You can use this to modify the value being set in the field, Return false
58182 * to cancel the change. The edit event object has the following properties <br />
58183 * <ul style="padding:5px;padding-left:16px;">
58184 * <li>editor - This editor</li>
58185 * <li>grid - This grid</li>
58186 * <li>record - The record being edited</li>
58187 * <li>field - The field name being edited</li>
58188 * <li>value - The value being set</li>
58189 * <li>originalValue - The original value for the field, before the edit.</li>
58190 * <li>row - The grid row index</li>
58191 * <li>column - The grid column index</li>
58192 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58194 * @param {Object} e An edit event (see above for description)
58196 "validateedit" : true
58198 this.on("bodyscroll", this.stopEditing, this);
58199 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58202 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58204 * @cfg {Number} clicksToEdit
58205 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58212 trackMouseOver: false, // causes very odd FF errors
58214 onCellDblClick : function(g, row, col){
58215 this.startEditing(row, col);
58218 onEditComplete : function(ed, value, startValue){
58219 this.editing = false;
58220 this.activeEditor = null;
58221 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58223 var field = this.colModel.getDataIndex(ed.col);
58228 originalValue: startValue,
58235 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58238 if(String(value) !== String(startValue)){
58240 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58241 r.set(field, e.value);
58242 // if we are dealing with a combo box..
58243 // then we also set the 'name' colum to be the displayField
58244 if (ed.field.displayField && ed.field.name) {
58245 r.set(ed.field.name, ed.field.el.dom.value);
58248 delete e.cancel; //?? why!!!
58249 this.fireEvent("afteredit", e);
58252 this.fireEvent("afteredit", e); // always fire it!
58254 this.view.focusCell(ed.row, ed.col);
58258 * Starts editing the specified for the specified row/column
58259 * @param {Number} rowIndex
58260 * @param {Number} colIndex
58262 startEditing : function(row, col){
58263 this.stopEditing();
58264 if(this.colModel.isCellEditable(col, row)){
58265 this.view.ensureVisible(row, col, true);
58267 var r = this.dataSource.getAt(row);
58268 var field = this.colModel.getDataIndex(col);
58269 var cell = Roo.get(this.view.getCell(row,col));
58274 value: r.data[field],
58279 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58280 this.editing = true;
58281 var ed = this.colModel.getCellEditor(col, row);
58287 ed.render(ed.parentEl || document.body);
58293 (function(){ // complex but required for focus issues in safari, ie and opera
58297 ed.on("complete", this.onEditComplete, this, {single: true});
58298 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58299 this.activeEditor = ed;
58300 var v = r.data[field];
58301 ed.startEdit(this.view.getCell(row, col), v);
58302 // combo's with 'displayField and name set
58303 if (ed.field.displayField && ed.field.name) {
58304 ed.field.el.dom.value = r.data[ed.field.name];
58308 }).defer(50, this);
58314 * Stops any active editing
58316 stopEditing : function(){
58317 if(this.activeEditor){
58318 this.activeEditor.completeEdit();
58320 this.activeEditor = null;
58324 * Called to get grid's drag proxy text, by default returns this.ddText.
58327 getDragDropText : function(){
58328 var count = this.selModel.getSelectedCell() ? 1 : 0;
58329 return String.format(this.ddText, count, count == 1 ? '' : 's');
58334 * Ext JS Library 1.1.1
58335 * Copyright(c) 2006-2007, Ext JS, LLC.
58337 * Originally Released Under LGPL - original licence link has changed is not relivant.
58340 * <script type="text/javascript">
58343 // private - not really -- you end up using it !
58344 // This is a support class used internally by the Grid components
58347 * @class Roo.grid.GridEditor
58348 * @extends Roo.Editor
58349 * Class for creating and editable grid elements.
58350 * @param {Object} config any settings (must include field)
58352 Roo.grid.GridEditor = function(field, config){
58353 if (!config && field.field) {
58355 field = Roo.factory(config.field, Roo.form);
58357 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58358 field.monitorTab = false;
58361 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58364 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58367 alignment: "tl-tl",
58370 cls: "x-small-editor x-grid-editor",
58375 * Ext JS Library 1.1.1
58376 * Copyright(c) 2006-2007, Ext JS, LLC.
58378 * Originally Released Under LGPL - original licence link has changed is not relivant.
58381 * <script type="text/javascript">
58386 Roo.grid.PropertyRecord = Roo.data.Record.create([
58387 {name:'name',type:'string'}, 'value'
58391 Roo.grid.PropertyStore = function(grid, source){
58393 this.store = new Roo.data.Store({
58394 recordType : Roo.grid.PropertyRecord
58396 this.store.on('update', this.onUpdate, this);
58398 this.setSource(source);
58400 Roo.grid.PropertyStore.superclass.constructor.call(this);
58405 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58406 setSource : function(o){
58408 this.store.removeAll();
58411 if(this.isEditableValue(o[k])){
58412 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58415 this.store.loadRecords({records: data}, {}, true);
58418 onUpdate : function(ds, record, type){
58419 if(type == Roo.data.Record.EDIT){
58420 var v = record.data['value'];
58421 var oldValue = record.modified['value'];
58422 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58423 this.source[record.id] = v;
58425 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58432 getProperty : function(row){
58433 return this.store.getAt(row);
58436 isEditableValue: function(val){
58437 if(val && val instanceof Date){
58439 }else if(typeof val == 'object' || typeof val == 'function'){
58445 setValue : function(prop, value){
58446 this.source[prop] = value;
58447 this.store.getById(prop).set('value', value);
58450 getSource : function(){
58451 return this.source;
58455 Roo.grid.PropertyColumnModel = function(grid, store){
58458 g.PropertyColumnModel.superclass.constructor.call(this, [
58459 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58460 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58462 this.store = store;
58463 this.bselect = Roo.DomHelper.append(document.body, {
58464 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58465 {tag: 'option', value: 'true', html: 'true'},
58466 {tag: 'option', value: 'false', html: 'false'}
58469 Roo.id(this.bselect);
58472 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58473 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58474 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58475 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58476 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58478 this.renderCellDelegate = this.renderCell.createDelegate(this);
58479 this.renderPropDelegate = this.renderProp.createDelegate(this);
58482 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58486 valueText : 'Value',
58488 dateFormat : 'm/j/Y',
58491 renderDate : function(dateVal){
58492 return dateVal.dateFormat(this.dateFormat);
58495 renderBool : function(bVal){
58496 return bVal ? 'true' : 'false';
58499 isCellEditable : function(colIndex, rowIndex){
58500 return colIndex == 1;
58503 getRenderer : function(col){
58505 this.renderCellDelegate : this.renderPropDelegate;
58508 renderProp : function(v){
58509 return this.getPropertyName(v);
58512 renderCell : function(val){
58514 if(val instanceof Date){
58515 rv = this.renderDate(val);
58516 }else if(typeof val == 'boolean'){
58517 rv = this.renderBool(val);
58519 return Roo.util.Format.htmlEncode(rv);
58522 getPropertyName : function(name){
58523 var pn = this.grid.propertyNames;
58524 return pn && pn[name] ? pn[name] : name;
58527 getCellEditor : function(colIndex, rowIndex){
58528 var p = this.store.getProperty(rowIndex);
58529 var n = p.data['name'], val = p.data['value'];
58531 if(typeof(this.grid.customEditors[n]) == 'string'){
58532 return this.editors[this.grid.customEditors[n]];
58534 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58535 return this.grid.customEditors[n];
58537 if(val instanceof Date){
58538 return this.editors['date'];
58539 }else if(typeof val == 'number'){
58540 return this.editors['number'];
58541 }else if(typeof val == 'boolean'){
58542 return this.editors['boolean'];
58544 return this.editors['string'];
58550 * @class Roo.grid.PropertyGrid
58551 * @extends Roo.grid.EditorGrid
58552 * This class represents the interface of a component based property grid control.
58553 * <br><br>Usage:<pre><code>
58554 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58562 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58563 * The container MUST have some type of size defined for the grid to fill. The container will be
58564 * automatically set to position relative if it isn't already.
58565 * @param {Object} config A config object that sets properties on this grid.
58567 Roo.grid.PropertyGrid = function(container, config){
58568 config = config || {};
58569 var store = new Roo.grid.PropertyStore(this);
58570 this.store = store;
58571 var cm = new Roo.grid.PropertyColumnModel(this, store);
58572 store.store.sort('name', 'ASC');
58573 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58576 enableColLock:false,
58577 enableColumnMove:false,
58579 trackMouseOver: false,
58582 this.getGridEl().addClass('x-props-grid');
58583 this.lastEditRow = null;
58584 this.on('columnresize', this.onColumnResize, this);
58587 * @event beforepropertychange
58588 * Fires before a property changes (return false to stop?)
58589 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58590 * @param {String} id Record Id
58591 * @param {String} newval New Value
58592 * @param {String} oldval Old Value
58594 "beforepropertychange": true,
58596 * @event propertychange
58597 * Fires after a property changes
58598 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58599 * @param {String} id Record Id
58600 * @param {String} newval New Value
58601 * @param {String} oldval Old Value
58603 "propertychange": true
58605 this.customEditors = this.customEditors || {};
58607 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58610 * @cfg {Object} customEditors map of colnames=> custom editors.
58611 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58612 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58613 * false disables editing of the field.
58617 * @cfg {Object} propertyNames map of property Names to their displayed value
58620 render : function(){
58621 Roo.grid.PropertyGrid.superclass.render.call(this);
58622 this.autoSize.defer(100, this);
58625 autoSize : function(){
58626 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58628 this.view.fitColumns();
58632 onColumnResize : function(){
58633 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58637 * Sets the data for the Grid
58638 * accepts a Key => Value object of all the elements avaiable.
58639 * @param {Object} data to appear in grid.
58641 setSource : function(source){
58642 this.store.setSource(source);
58646 * Gets all the data from the grid.
58647 * @return {Object} data data stored in grid
58649 getSource : function(){
58650 return this.store.getSource();
58659 * @class Roo.grid.Calendar
58660 * @extends Roo.util.Grid
58661 * This class extends the Grid to provide a calendar widget
58662 * <br><br>Usage:<pre><code>
58663 var grid = new Roo.grid.Calendar("my-container-id", {
58666 selModel: mySelectionModel,
58667 autoSizeColumns: true,
58668 monitorWindowResize: false,
58669 trackMouseOver: true
58670 eventstore : real data store..
58676 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58677 * The container MUST have some type of size defined for the grid to fill. The container will be
58678 * automatically set to position relative if it isn't already.
58679 * @param {Object} config A config object that sets properties on this grid.
58681 Roo.grid.Calendar = function(container, config){
58682 // initialize the container
58683 this.container = Roo.get(container);
58684 this.container.update("");
58685 this.container.setStyle("overflow", "hidden");
58686 this.container.addClass('x-grid-container');
58688 this.id = this.container.id;
58690 Roo.apply(this, config);
58691 // check and correct shorthanded configs
58695 for (var r = 0;r < 6;r++) {
58698 for (var c =0;c < 7;c++) {
58702 if (this.eventStore) {
58703 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58704 this.eventStore.on('load',this.onLoad, this);
58705 this.eventStore.on('beforeload',this.clearEvents, this);
58709 this.dataSource = new Roo.data.Store({
58710 proxy: new Roo.data.MemoryProxy(rows),
58711 reader: new Roo.data.ArrayReader({}, [
58712 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58715 this.dataSource.load();
58716 this.ds = this.dataSource;
58717 this.ds.xmodule = this.xmodule || false;
58720 var cellRender = function(v,x,r)
58722 return String.format(
58723 '<div class="fc-day fc-widget-content"><div>' +
58724 '<div class="fc-event-container"></div>' +
58725 '<div class="fc-day-number">{0}</div>'+
58727 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58728 '</div></div>', v);
58733 this.colModel = new Roo.grid.ColumnModel( [
58735 xtype: 'ColumnModel',
58737 dataIndex : 'weekday0',
58739 renderer : cellRender
58742 xtype: 'ColumnModel',
58744 dataIndex : 'weekday1',
58746 renderer : cellRender
58749 xtype: 'ColumnModel',
58751 dataIndex : 'weekday2',
58752 header : 'Tuesday',
58753 renderer : cellRender
58756 xtype: 'ColumnModel',
58758 dataIndex : 'weekday3',
58759 header : 'Wednesday',
58760 renderer : cellRender
58763 xtype: 'ColumnModel',
58765 dataIndex : 'weekday4',
58766 header : 'Thursday',
58767 renderer : cellRender
58770 xtype: 'ColumnModel',
58772 dataIndex : 'weekday5',
58774 renderer : cellRender
58777 xtype: 'ColumnModel',
58779 dataIndex : 'weekday6',
58780 header : 'Saturday',
58781 renderer : cellRender
58784 this.cm = this.colModel;
58785 this.cm.xmodule = this.xmodule || false;
58789 //this.selModel = new Roo.grid.CellSelectionModel();
58790 //this.sm = this.selModel;
58791 //this.selModel.init(this);
58795 this.container.setWidth(this.width);
58799 this.container.setHeight(this.height);
58806 * The raw click event for the entire grid.
58807 * @param {Roo.EventObject} e
58812 * The raw dblclick event for the entire grid.
58813 * @param {Roo.EventObject} e
58817 * @event contextmenu
58818 * The raw contextmenu event for the entire grid.
58819 * @param {Roo.EventObject} e
58821 "contextmenu" : true,
58824 * The raw mousedown event for the entire grid.
58825 * @param {Roo.EventObject} e
58827 "mousedown" : true,
58830 * The raw mouseup event for the entire grid.
58831 * @param {Roo.EventObject} e
58836 * The raw mouseover event for the entire grid.
58837 * @param {Roo.EventObject} e
58839 "mouseover" : true,
58842 * The raw mouseout event for the entire grid.
58843 * @param {Roo.EventObject} e
58848 * The raw keypress event for the entire grid.
58849 * @param {Roo.EventObject} e
58854 * The raw keydown event for the entire grid.
58855 * @param {Roo.EventObject} e
58863 * Fires when a cell is clicked
58864 * @param {Grid} this
58865 * @param {Number} rowIndex
58866 * @param {Number} columnIndex
58867 * @param {Roo.EventObject} e
58869 "cellclick" : true,
58871 * @event celldblclick
58872 * Fires when a cell is double clicked
58873 * @param {Grid} this
58874 * @param {Number} rowIndex
58875 * @param {Number} columnIndex
58876 * @param {Roo.EventObject} e
58878 "celldblclick" : true,
58881 * Fires when a row is clicked
58882 * @param {Grid} this
58883 * @param {Number} rowIndex
58884 * @param {Roo.EventObject} e
58888 * @event rowdblclick
58889 * Fires when a row is double clicked
58890 * @param {Grid} this
58891 * @param {Number} rowIndex
58892 * @param {Roo.EventObject} e
58894 "rowdblclick" : true,
58896 * @event headerclick
58897 * Fires when a header is clicked
58898 * @param {Grid} this
58899 * @param {Number} columnIndex
58900 * @param {Roo.EventObject} e
58902 "headerclick" : true,
58904 * @event headerdblclick
58905 * Fires when a header cell is double clicked
58906 * @param {Grid} this
58907 * @param {Number} columnIndex
58908 * @param {Roo.EventObject} e
58910 "headerdblclick" : true,
58912 * @event rowcontextmenu
58913 * Fires when a row is right clicked
58914 * @param {Grid} this
58915 * @param {Number} rowIndex
58916 * @param {Roo.EventObject} e
58918 "rowcontextmenu" : true,
58920 * @event cellcontextmenu
58921 * Fires when a cell is right clicked
58922 * @param {Grid} this
58923 * @param {Number} rowIndex
58924 * @param {Number} cellIndex
58925 * @param {Roo.EventObject} e
58927 "cellcontextmenu" : true,
58929 * @event headercontextmenu
58930 * Fires when a header is right clicked
58931 * @param {Grid} this
58932 * @param {Number} columnIndex
58933 * @param {Roo.EventObject} e
58935 "headercontextmenu" : true,
58937 * @event bodyscroll
58938 * Fires when the body element is scrolled
58939 * @param {Number} scrollLeft
58940 * @param {Number} scrollTop
58942 "bodyscroll" : true,
58944 * @event columnresize
58945 * Fires when the user resizes a column
58946 * @param {Number} columnIndex
58947 * @param {Number} newSize
58949 "columnresize" : true,
58951 * @event columnmove
58952 * Fires when the user moves a column
58953 * @param {Number} oldIndex
58954 * @param {Number} newIndex
58956 "columnmove" : true,
58959 * Fires when row(s) start being dragged
58960 * @param {Grid} this
58961 * @param {Roo.GridDD} dd The drag drop object
58962 * @param {event} e The raw browser event
58964 "startdrag" : true,
58967 * Fires when a drag operation is complete
58968 * @param {Grid} this
58969 * @param {Roo.GridDD} dd The drag drop object
58970 * @param {event} e The raw browser event
58975 * Fires when dragged row(s) are dropped on a valid DD target
58976 * @param {Grid} this
58977 * @param {Roo.GridDD} dd The drag drop object
58978 * @param {String} targetId The target drag drop object
58979 * @param {event} e The raw browser event
58984 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
58985 * @param {Grid} this
58986 * @param {Roo.GridDD} dd The drag drop object
58987 * @param {String} targetId The target drag drop object
58988 * @param {event} e The raw browser event
58993 * Fires when the dragged row(s) first cross another DD target while being dragged
58994 * @param {Grid} this
58995 * @param {Roo.GridDD} dd The drag drop object
58996 * @param {String} targetId The target drag drop object
58997 * @param {event} e The raw browser event
58999 "dragenter" : true,
59002 * Fires when the dragged row(s) leave another DD target while being dragged
59003 * @param {Grid} this
59004 * @param {Roo.GridDD} dd The drag drop object
59005 * @param {String} targetId The target drag drop object
59006 * @param {event} e The raw browser event
59011 * Fires when a row is rendered, so you can change add a style to it.
59012 * @param {GridView} gridview The grid view
59013 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59019 * Fires when the grid is rendered
59020 * @param {Grid} grid
59025 * Fires when a date is selected
59026 * @param {DatePicker} this
59027 * @param {Date} date The selected date
59031 * @event monthchange
59032 * Fires when the displayed month changes
59033 * @param {DatePicker} this
59034 * @param {Date} date The selected month
59036 'monthchange': true,
59038 * @event evententer
59039 * Fires when mouse over an event
59040 * @param {Calendar} this
59041 * @param {event} Event
59043 'evententer': true,
59045 * @event eventleave
59046 * Fires when the mouse leaves an
59047 * @param {Calendar} this
59050 'eventleave': true,
59052 * @event eventclick
59053 * Fires when the mouse click an
59054 * @param {Calendar} this
59057 'eventclick': true,
59059 * @event eventrender
59060 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59061 * @param {Calendar} this
59062 * @param {data} data to be modified
59064 'eventrender': true
59068 Roo.grid.Grid.superclass.constructor.call(this);
59069 this.on('render', function() {
59070 this.view.el.addClass('x-grid-cal');
59072 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59076 if (!Roo.grid.Calendar.style) {
59077 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59080 '.x-grid-cal .x-grid-col' : {
59081 height: 'auto !important',
59082 'vertical-align': 'top'
59084 '.x-grid-cal .fc-event-hori' : {
59095 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59097 * @cfg {Store} eventStore The store that loads events.
59102 activeDate : false,
59105 monitorWindowResize : false,
59108 resizeColumns : function() {
59109 var col = (this.view.el.getWidth() / 7) - 3;
59110 // loop through cols, and setWidth
59111 for(var i =0 ; i < 7 ; i++){
59112 this.cm.setColumnWidth(i, col);
59115 setDate :function(date) {
59117 Roo.log('setDate?');
59119 this.resizeColumns();
59120 var vd = this.activeDate;
59121 this.activeDate = date;
59122 // if(vd && this.el){
59123 // var t = date.getTime();
59124 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59125 // Roo.log('using add remove');
59127 // this.fireEvent('monthchange', this, date);
59129 // this.cells.removeClass("fc-state-highlight");
59130 // this.cells.each(function(c){
59131 // if(c.dateValue == t){
59132 // c.addClass("fc-state-highlight");
59133 // setTimeout(function(){
59134 // try{c.dom.firstChild.focus();}catch(e){}
59144 var days = date.getDaysInMonth();
59146 var firstOfMonth = date.getFirstDateOfMonth();
59147 var startingPos = firstOfMonth.getDay()-this.startDay;
59149 if(startingPos < this.startDay){
59153 var pm = date.add(Date.MONTH, -1);
59154 var prevStart = pm.getDaysInMonth()-startingPos;
59158 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59160 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59161 //this.cells.addClassOnOver('fc-state-hover');
59163 var cells = this.cells.elements;
59164 var textEls = this.textNodes;
59166 //Roo.each(cells, function(cell){
59167 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59170 days += startingPos;
59172 // convert everything to numbers so it's fast
59173 var day = 86400000;
59174 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59177 //Roo.log(prevStart);
59179 var today = new Date().clearTime().getTime();
59180 var sel = date.clearTime().getTime();
59181 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59182 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59183 var ddMatch = this.disabledDatesRE;
59184 var ddText = this.disabledDatesText;
59185 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59186 var ddaysText = this.disabledDaysText;
59187 var format = this.format;
59189 var setCellClass = function(cal, cell){
59191 //Roo.log('set Cell Class');
59193 var t = d.getTime();
59198 cell.dateValue = t;
59200 cell.className += " fc-today";
59201 cell.className += " fc-state-highlight";
59202 cell.title = cal.todayText;
59205 // disable highlight in other month..
59206 cell.className += " fc-state-highlight";
59211 //cell.className = " fc-state-disabled";
59212 cell.title = cal.minText;
59216 //cell.className = " fc-state-disabled";
59217 cell.title = cal.maxText;
59221 if(ddays.indexOf(d.getDay()) != -1){
59222 // cell.title = ddaysText;
59223 // cell.className = " fc-state-disabled";
59226 if(ddMatch && format){
59227 var fvalue = d.dateFormat(format);
59228 if(ddMatch.test(fvalue)){
59229 cell.title = ddText.replace("%0", fvalue);
59230 cell.className = " fc-state-disabled";
59234 if (!cell.initialClassName) {
59235 cell.initialClassName = cell.dom.className;
59238 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59243 for(; i < startingPos; i++) {
59244 cells[i].dayName = (++prevStart);
59245 Roo.log(textEls[i]);
59246 d.setDate(d.getDate()+1);
59248 //cells[i].className = "fc-past fc-other-month";
59249 setCellClass(this, cells[i]);
59254 for(; i < days; i++){
59255 intDay = i - startingPos + 1;
59256 cells[i].dayName = (intDay);
59257 d.setDate(d.getDate()+1);
59259 cells[i].className = ''; // "x-date-active";
59260 setCellClass(this, cells[i]);
59264 for(; i < 42; i++) {
59265 //textEls[i].innerHTML = (++extraDays);
59267 d.setDate(d.getDate()+1);
59268 cells[i].dayName = (++extraDays);
59269 cells[i].className = "fc-future fc-other-month";
59270 setCellClass(this, cells[i]);
59273 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59275 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59277 // this will cause all the cells to mis
59280 for (var r = 0;r < 6;r++) {
59281 for (var c =0;c < 7;c++) {
59282 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59286 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59287 for(i=0;i<cells.length;i++) {
59289 this.cells.elements[i].dayName = cells[i].dayName ;
59290 this.cells.elements[i].className = cells[i].className;
59291 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59292 this.cells.elements[i].title = cells[i].title ;
59293 this.cells.elements[i].dateValue = cells[i].dateValue ;
59299 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59300 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59302 ////if(totalRows != 6){
59303 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59304 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59307 this.fireEvent('monthchange', this, date);
59312 * Returns the grid's SelectionModel.
59313 * @return {SelectionModel}
59315 getSelectionModel : function(){
59316 if(!this.selModel){
59317 this.selModel = new Roo.grid.CellSelectionModel();
59319 return this.selModel;
59323 this.eventStore.load()
59329 findCell : function(dt) {
59330 dt = dt.clearTime().getTime();
59332 this.cells.each(function(c){
59333 //Roo.log("check " +c.dateValue + '?=' + dt);
59334 if(c.dateValue == dt){
59344 findCells : function(rec) {
59345 var s = rec.data.start_dt.clone().clearTime().getTime();
59347 var e= rec.data.end_dt.clone().clearTime().getTime();
59350 this.cells.each(function(c){
59351 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59353 if(c.dateValue > e){
59356 if(c.dateValue < s){
59365 findBestRow: function(cells)
59369 for (var i =0 ; i < cells.length;i++) {
59370 ret = Math.max(cells[i].rows || 0,ret);
59377 addItem : function(rec)
59379 // look for vertical location slot in
59380 var cells = this.findCells(rec);
59382 rec.row = this.findBestRow(cells);
59384 // work out the location.
59388 for(var i =0; i < cells.length; i++) {
59396 if (crow.start.getY() == cells[i].getY()) {
59398 crow.end = cells[i];
59414 for (var i = 0; i < cells.length;i++) {
59415 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59422 clearEvents: function() {
59424 if (!this.eventStore.getCount()) {
59427 // reset number of rows in cells.
59428 Roo.each(this.cells.elements, function(c){
59432 this.eventStore.each(function(e) {
59433 this.clearEvent(e);
59438 clearEvent : function(ev)
59441 Roo.each(ev.els, function(el) {
59442 el.un('mouseenter' ,this.onEventEnter, this);
59443 el.un('mouseleave' ,this.onEventLeave, this);
59451 renderEvent : function(ev,ctr) {
59453 ctr = this.view.el.select('.fc-event-container',true).first();
59457 this.clearEvent(ev);
59463 var cells = ev.cells;
59464 var rows = ev.rows;
59465 this.fireEvent('eventrender', this, ev);
59467 for(var i =0; i < rows.length; i++) {
59471 cls += ' fc-event-start';
59473 if ((i+1) == rows.length) {
59474 cls += ' fc-event-end';
59477 //Roo.log(ev.data);
59478 // how many rows should it span..
59479 var cg = this.eventTmpl.append(ctr,Roo.apply({
59482 }, ev.data) , true);
59485 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59486 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59487 cg.on('click', this.onEventClick, this, ev);
59491 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59492 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59495 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59496 cg.setWidth(ebox.right - sbox.x -2);
59500 renderEvents: function()
59502 // first make sure there is enough space..
59504 if (!this.eventTmpl) {
59505 this.eventTmpl = new Roo.Template(
59506 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59507 '<div class="fc-event-inner">' +
59508 '<span class="fc-event-time">{time}</span>' +
59509 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59511 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59519 this.cells.each(function(c) {
59520 //Roo.log(c.select('.fc-day-content div',true).first());
59521 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59524 var ctr = this.view.el.select('.fc-event-container',true).first();
59527 this.eventStore.each(function(ev){
59529 this.renderEvent(ev);
59533 this.view.layout();
59537 onEventEnter: function (e, el,event,d) {
59538 this.fireEvent('evententer', this, el, event);
59541 onEventLeave: function (e, el,event,d) {
59542 this.fireEvent('eventleave', this, el, event);
59545 onEventClick: function (e, el,event,d) {
59546 this.fireEvent('eventclick', this, el, event);
59549 onMonthChange: function () {
59553 onLoad: function () {
59555 //Roo.log('calendar onload');
59557 if(this.eventStore.getCount() > 0){
59561 this.eventStore.each(function(d){
59566 if (typeof(add.end_dt) == 'undefined') {
59567 Roo.log("Missing End time in calendar data: ");
59571 if (typeof(add.start_dt) == 'undefined') {
59572 Roo.log("Missing Start time in calendar data: ");
59576 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59577 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59578 add.id = add.id || d.id;
59579 add.title = add.title || '??';
59587 this.renderEvents();
59597 render : function ()
59601 if (!this.view.el.hasClass('course-timesheet')) {
59602 this.view.el.addClass('course-timesheet');
59604 if (this.tsStyle) {
59609 Roo.log(_this.grid.view.el.getWidth());
59612 this.tsStyle = Roo.util.CSS.createStyleSheet({
59613 '.course-timesheet .x-grid-row' : {
59616 '.x-grid-row td' : {
59617 'vertical-align' : 0
59619 '.course-edit-link' : {
59621 'text-overflow' : 'ellipsis',
59622 'overflow' : 'hidden',
59623 'white-space' : 'nowrap',
59624 'cursor' : 'pointer'
59629 '.de-act-sup-link' : {
59630 'color' : 'purple',
59631 'text-decoration' : 'line-through'
59635 'text-decoration' : 'line-through'
59637 '.course-timesheet .course-highlight' : {
59638 'border-top-style': 'dashed !important',
59639 'border-bottom-bottom': 'dashed !important'
59641 '.course-timesheet .course-item' : {
59642 'font-family' : 'tahoma, arial, helvetica',
59643 'font-size' : '11px',
59644 'overflow' : 'hidden',
59645 'padding-left' : '10px',
59646 'padding-right' : '10px',
59647 'padding-top' : '10px'
59655 monitorWindowResize : false,
59656 cellrenderer : function(v,x,r)
59661 xtype: 'CellSelectionModel',
59668 beforeload : function (_self, options)
59670 options.params = options.params || {};
59671 options.params._month = _this.monthField.getValue();
59672 options.params.limit = 9999;
59673 options.params['sort'] = 'when_dt';
59674 options.params['dir'] = 'ASC';
59675 this.proxy.loadResponse = this.loadResponse;
59677 //this.addColumns();
59679 load : function (_self, records, options)
59681 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59682 // if you click on the translation.. you can edit it...
59683 var el = Roo.get(this);
59684 var id = el.dom.getAttribute('data-id');
59685 var d = el.dom.getAttribute('data-date');
59686 var t = el.dom.getAttribute('data-time');
59687 //var id = this.child('span').dom.textContent;
59690 Pman.Dialog.CourseCalendar.show({
59694 productitem_active : id ? 1 : 0
59696 _this.grid.ds.load({});
59701 _this.panel.fireEvent('resize', [ '', '' ]);
59704 loadResponse : function(o, success, response){
59705 // this is overridden on before load..
59707 Roo.log("our code?");
59708 //Roo.log(success);
59709 //Roo.log(response)
59710 delete this.activeRequest;
59712 this.fireEvent("loadexception", this, o, response);
59713 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59718 result = o.reader.read(response);
59720 Roo.log("load exception?");
59721 this.fireEvent("loadexception", this, o, response, e);
59722 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59725 Roo.log("ready...");
59726 // loop through result.records;
59727 // and set this.tdate[date] = [] << array of records..
59729 Roo.each(result.records, function(r){
59731 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59732 _this.tdata[r.data.when_dt.format('j')] = [];
59734 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59737 //Roo.log(_this.tdata);
59739 result.records = [];
59740 result.totalRecords = 6;
59742 // let's generate some duumy records for the rows.
59743 //var st = _this.dateField.getValue();
59745 // work out monday..
59746 //st = st.add(Date.DAY, -1 * st.format('w'));
59748 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59750 var firstOfMonth = date.getFirstDayOfMonth();
59751 var days = date.getDaysInMonth();
59753 var firstAdded = false;
59754 for (var i = 0; i < result.totalRecords ; i++) {
59755 //var d= st.add(Date.DAY, i);
59758 for(var w = 0 ; w < 7 ; w++){
59759 if(!firstAdded && firstOfMonth != w){
59766 var dd = (d > 0 && d < 10) ? "0"+d : d;
59767 row['weekday'+w] = String.format(
59768 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59769 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59771 date.format('Y-m-')+dd
59774 if(typeof(_this.tdata[d]) != 'undefined'){
59775 Roo.each(_this.tdata[d], function(r){
59779 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59780 if(r.parent_id*1>0){
59781 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59784 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59785 deactive = 'de-act-link';
59788 row['weekday'+w] += String.format(
59789 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59791 r.product_id_name, //1
59792 r.when_dt.format('h:ia'), //2
59802 // only do this if something added..
59804 result.records.push(_this.grid.dataSource.reader.newRow(row));
59808 // push it twice. (second one with an hour..
59812 this.fireEvent("load", this, o, o.request.arg);
59813 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59815 sortInfo : {field: 'when_dt', direction : 'ASC' },
59817 xtype: 'HttpProxy',
59820 url : baseURL + '/Roo/Shop_course.php'
59823 xtype: 'JsonReader',
59840 'name': 'parent_id',
59844 'name': 'product_id',
59848 'name': 'productitem_id',
59866 click : function (_self, e)
59868 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59869 sd.setMonth(sd.getMonth()-1);
59870 _this.monthField.setValue(sd.format('Y-m-d'));
59871 _this.grid.ds.load({});
59877 xtype: 'Separator',
59881 xtype: 'MonthField',
59884 render : function (_self)
59886 _this.monthField = _self;
59887 // _this.monthField.set today
59889 select : function (combo, date)
59891 _this.grid.ds.load({});
59894 value : (function() { return new Date(); })()
59897 xtype: 'Separator',
59903 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
59913 click : function (_self, e)
59915 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59916 sd.setMonth(sd.getMonth()+1);
59917 _this.monthField.setValue(sd.format('Y-m-d'));
59918 _this.grid.ds.load({});
59931 * Ext JS Library 1.1.1
59932 * Copyright(c) 2006-2007, Ext JS, LLC.
59934 * Originally Released Under LGPL - original licence link has changed is not relivant.
59937 * <script type="text/javascript">
59941 * @class Roo.LoadMask
59942 * A simple utility class for generically masking elements while loading data. If the element being masked has
59943 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
59944 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
59945 * element's UpdateManager load indicator and will be destroyed after the initial load.
59947 * Create a new LoadMask
59948 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
59949 * @param {Object} config The config object
59951 Roo.LoadMask = function(el, config){
59952 this.el = Roo.get(el);
59953 Roo.apply(this, config);
59955 this.store.on('beforeload', this.onBeforeLoad, this);
59956 this.store.on('load', this.onLoad, this);
59957 this.store.on('loadexception', this.onLoadException, this);
59958 this.removeMask = false;
59960 var um = this.el.getUpdateManager();
59961 um.showLoadIndicator = false; // disable the default indicator
59962 um.on('beforeupdate', this.onBeforeLoad, this);
59963 um.on('update', this.onLoad, this);
59964 um.on('failure', this.onLoad, this);
59965 this.removeMask = true;
59969 Roo.LoadMask.prototype = {
59971 * @cfg {Boolean} removeMask
59972 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
59973 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
59976 * @cfg {String} msg
59977 * The text to display in a centered loading message box (defaults to 'Loading...')
59979 msg : 'Loading...',
59981 * @cfg {String} msgCls
59982 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
59984 msgCls : 'x-mask-loading',
59987 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
59993 * Disables the mask to prevent it from being displayed
59995 disable : function(){
59996 this.disabled = true;
60000 * Enables the mask so that it can be displayed
60002 enable : function(){
60003 this.disabled = false;
60006 onLoadException : function()
60008 Roo.log(arguments);
60010 if (typeof(arguments[3]) != 'undefined') {
60011 Roo.MessageBox.alert("Error loading",arguments[3]);
60015 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60016 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60025 this.el.unmask(this.removeMask);
60028 onLoad : function()
60030 this.el.unmask(this.removeMask);
60034 onBeforeLoad : function(){
60035 if(!this.disabled){
60036 this.el.mask(this.msg, this.msgCls);
60041 destroy : function(){
60043 this.store.un('beforeload', this.onBeforeLoad, this);
60044 this.store.un('load', this.onLoad, this);
60045 this.store.un('loadexception', this.onLoadException, this);
60047 var um = this.el.getUpdateManager();
60048 um.un('beforeupdate', this.onBeforeLoad, this);
60049 um.un('update', this.onLoad, this);
60050 um.un('failure', this.onLoad, this);
60055 * Ext JS Library 1.1.1
60056 * Copyright(c) 2006-2007, Ext JS, LLC.
60058 * Originally Released Under LGPL - original licence link has changed is not relivant.
60061 * <script type="text/javascript">
60066 * @class Roo.XTemplate
60067 * @extends Roo.Template
60068 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60070 var t = new Roo.XTemplate(
60071 '<select name="{name}">',
60072 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60076 // then append, applying the master template values
60079 * Supported features:
60084 {a_variable} - output encoded.
60085 {a_variable.format:("Y-m-d")} - call a method on the variable
60086 {a_variable:raw} - unencoded output
60087 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60088 {a_variable:this.method_on_template(...)} - call a method on the template object.
60093 <tpl for="a_variable or condition.."></tpl>
60094 <tpl if="a_variable or condition"></tpl>
60095 <tpl exec="some javascript"></tpl>
60096 <tpl name="named_template"></tpl> (experimental)
60098 <tpl for="."></tpl> - just iterate the property..
60099 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60103 Roo.XTemplate = function()
60105 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60112 Roo.extend(Roo.XTemplate, Roo.Template, {
60115 * The various sub templates
60120 * basic tag replacing syntax
60123 * // you can fake an object call by doing this
60127 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60130 * compile the template
60132 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60135 compile: function()
60139 s = ['<tpl>', s, '</tpl>'].join('');
60141 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60142 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60143 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60144 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60145 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60150 while(true == !!(m = s.match(re))){
60151 var forMatch = m[0].match(nameRe),
60152 ifMatch = m[0].match(ifRe),
60153 execMatch = m[0].match(execRe),
60154 namedMatch = m[0].match(namedRe),
60159 name = forMatch && forMatch[1] ? forMatch[1] : '';
60162 // if - puts fn into test..
60163 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60165 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60170 // exec - calls a function... returns empty if true is returned.
60171 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60173 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60181 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60182 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60183 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60186 var uid = namedMatch ? namedMatch[1] : id;
60190 id: namedMatch ? namedMatch[1] : id,
60197 s = s.replace(m[0], '');
60199 s = s.replace(m[0], '{xtpl'+ id + '}');
60204 for(var i = tpls.length-1; i >= 0; --i){
60205 this.compileTpl(tpls[i]);
60206 this.tpls[tpls[i].id] = tpls[i];
60208 this.master = tpls[tpls.length-1];
60212 * same as applyTemplate, except it's done to one of the subTemplates
60213 * when using named templates, you can do:
60215 * var str = pl.applySubTemplate('your-name', values);
60218 * @param {Number} id of the template
60219 * @param {Object} values to apply to template
60220 * @param {Object} parent (normaly the instance of this object)
60222 applySubTemplate : function(id, values, parent)
60226 var t = this.tpls[id];
60230 if(t.test && !t.test.call(this, values, parent)){
60234 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60235 Roo.log(e.toString());
60241 if(t.exec && t.exec.call(this, values, parent)){
60245 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60246 Roo.log(e.toString());
60251 var vs = t.target ? t.target.call(this, values, parent) : values;
60252 parent = t.target ? values : parent;
60253 if(t.target && vs instanceof Array){
60255 for(var i = 0, len = vs.length; i < len; i++){
60256 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60258 return buf.join('');
60260 return t.compiled.call(this, vs, parent);
60262 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60263 Roo.log(e.toString());
60264 Roo.log(t.compiled);
60269 compileTpl : function(tpl)
60271 var fm = Roo.util.Format;
60272 var useF = this.disableFormats !== true;
60273 var sep = Roo.isGecko ? "+" : ",";
60274 var undef = function(str) {
60275 Roo.log("Property not found :" + str);
60279 var fn = function(m, name, format, args)
60281 //Roo.log(arguments);
60282 args = args ? args.replace(/\\'/g,"'") : args;
60283 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60284 if (typeof(format) == 'undefined') {
60285 format= 'htmlEncode';
60287 if (format == 'raw' ) {
60291 if(name.substr(0, 4) == 'xtpl'){
60292 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60295 // build an array of options to determine if value is undefined..
60297 // basically get 'xxxx.yyyy' then do
60298 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60299 // (function () { Roo.log("Property not found"); return ''; })() :
60304 Roo.each(name.split('.'), function(st) {
60305 lookfor += (lookfor.length ? '.': '') + st;
60306 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60309 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60312 if(format && useF){
60314 args = args ? ',' + args : "";
60316 if(format.substr(0, 5) != "this."){
60317 format = "fm." + format + '(';
60319 format = 'this.call("'+ format.substr(5) + '", ';
60323 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60327 // called with xxyx.yuu:(test,test)
60329 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60331 // raw.. - :raw modifier..
60332 return "'"+ sep + udef_st + name + ")"+sep+"'";
60336 // branched to use + in gecko and [].join() in others
60338 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60339 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60342 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60343 body.push(tpl.body.replace(/(\r\n|\n)/g,
60344 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60345 body.push("'].join('');};};");
60346 body = body.join('');
60349 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60351 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60357 applyTemplate : function(values){
60358 return this.master.compiled.call(this, values, {});
60359 //var s = this.subs;
60362 apply : function(){
60363 return this.applyTemplate.apply(this, arguments);
60368 Roo.XTemplate.from = function(el){
60369 el = Roo.getDom(el);
60370 return new Roo.XTemplate(el.value || el.innerHTML);