4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70 window.addEventListener('touchstart', function __set_has_touch__ () {
72 window.removeEventListener('touchstart', __set_has_touch__);
74 return false; // no touch on chrome!?
76 document.createEvent("TouchEvent");
83 // remove css image flicker
86 document.execCommand("BackgroundImageCache", false, true);
92 * True if the browser is in strict mode
97 * True if the page is running over SSL
102 * True when the document is fully initialized and ready for action
107 * Turn on debugging output (currently only the factory uses this)
114 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117 enableGarbageCollector : true,
120 * True to automatically purge event listeners after uncaching an element (defaults to false).
121 * Note: this only happens if enableGarbageCollector is true.
124 enableListenerCollection:false,
127 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128 * the IE insecure content warning (defaults to javascript:false).
131 SSL_SECURE_URL : "javascript:false",
134 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140 emptyFn : function(){},
143 * Copies all the properties of config to obj if they don't already exist.
144 * @param {Object} obj The receiver of the properties
145 * @param {Object} config The source of the properties
146 * @return {Object} returns obj
148 applyIf : function(o, c){
151 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
158 * Applies event listeners to elements by selectors when the document is ready.
159 * The event name is specified with an @ suffix.
162 // add a listener for click on all anchors in element with id foo
163 '#foo a@click' : function(e, t){
167 // add the same listener to multiple selectors (separated by comma BEFORE the @)
168 '#foo a, #bar span.some-class@mouseover' : function(){
173 * @param {Object} obj The list of behaviors to apply
175 addBehaviors : function(o){
177 Roo.onReady(function(){
182 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184 var parts = b.split('@');
185 if(parts[1]){ // for Object prototype breakers
188 cache[s] = Roo.select(s);
190 cache[s].on(parts[1], o[b]);
197 * Generates unique ids. If the element already has an id, it is unchanged
198 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200 * @return {String} The generated Id.
202 id : function(el, prefix){
203 prefix = prefix || "roo-gen";
205 var id = prefix + (++idSeed);
206 return el ? (el.id ? el.id : (el.id = id)) : id;
211 * Extends one class with another class and optionally overrides members with the passed literal. This class
212 * also adds the function "override()" to the class that can be used to override
213 * members on an instance.
214 * @param {Object} subclass The class inheriting the functionality
215 * @param {Object} superclass The class being extended
216 * @param {Object} overrides (optional) A literal with members
221 var io = function(o){
226 return function(sb, sp, overrides){
227 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230 sb = function(){sp.apply(this, arguments);};
232 var F = function(){}, sbp, spp = sp.prototype;
234 sbp = sb.prototype = new F();
238 if(spp.constructor == Object.prototype.constructor){
243 sb.override = function(o){
247 Roo.override(sb, overrides);
253 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255 Roo.override(MyClass, {
256 newMethod1: function(){
259 newMethod2: function(foo){
264 * @param {Object} origclass The class to override
265 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
266 * containing one or more methods.
269 override : function(origclass, overrides){
271 var p = origclass.prototype;
272 for(var method in overrides){
273 p[method] = overrides[method];
278 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
284 * @param {String} namespace1
285 * @param {String} namespace2
286 * @param {String} etc
289 namespace : function(){
290 var a=arguments, o=null, i, j, d, rt;
291 for (i=0; i<a.length; ++i) {
295 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296 for (j=1; j<d.length; ++j) {
297 o[d[j]]=o[d[j]] || {};
303 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
308 * @param {String} classname
309 * @param {String} namespace (optional)
313 factory : function(c, ns)
315 // no xtype, no ns or c.xns - or forced off by c.xns
316 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
319 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320 if (c.constructor == ns[c.xtype]) {// already created...
324 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325 var ret = new ns[c.xtype](c);
329 c.xns = false; // prevent recursion..
333 * Logs to console if it can.
335 * @param {String|Object} string
340 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
347 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
351 urlEncode : function(o){
357 var ov = o[key], k = Roo.encodeURIComponent(key);
358 var type = typeof ov;
359 if(type == 'undefined'){
361 }else if(type != "function" && type != "object"){
362 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363 }else if(ov instanceof Array){
365 for(var i = 0, len = ov.length; i < len; i++) {
366 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
377 * Safe version of encodeURIComponent
378 * @param {String} data
382 encodeURIComponent : function (data)
385 return encodeURIComponent(data);
386 } catch(e) {} // should be an uri encode error.
388 if (data == '' || data == null){
391 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392 function nibble_to_hex(nibble){
393 var chars = '0123456789ABCDEF';
394 return chars.charAt(nibble);
396 data = data.toString();
398 for(var i=0; i<data.length; i++){
399 var c = data.charCodeAt(i);
400 var bs = new Array();
403 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406 bs[3] = 0x80 | (c & 0x3F);
407 }else if (c > 0x800){
409 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411 bs[2] = 0x80 | (c & 0x3F);
414 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415 bs[1] = 0x80 | (c & 0x3F);
420 for(var j=0; j<bs.length; j++){
422 var hex = nibble_to_hex((b & 0xF0) >>> 4)
423 + nibble_to_hex(b &0x0F);
432 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
433 * @param {String} string
434 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435 * @return {Object} A literal with members
437 urlDecode : function(string, overwrite){
438 if(!string || !string.length){
442 var pairs = string.split('&');
443 var pair, name, value;
444 for(var i = 0, len = pairs.length; i < len; i++){
445 pair = pairs[i].split('=');
446 name = decodeURIComponent(pair[0]);
447 value = decodeURIComponent(pair[1]);
448 if(overwrite !== true){
449 if(typeof obj[name] == "undefined"){
451 }else if(typeof obj[name] == "string"){
452 obj[name] = [obj[name]];
453 obj[name].push(value);
455 obj[name].push(value);
465 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466 * passed array is not really an array, your function is called once with it.
467 * The supplied function is called with (Object item, Number index, Array allItems).
468 * @param {Array/NodeList/Mixed} array
469 * @param {Function} fn
470 * @param {Object} scope
472 each : function(array, fn, scope){
473 if(typeof array.length == "undefined" || typeof array == "string"){
476 for(var i = 0, len = array.length; i < len; i++){
477 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482 combine : function(){
483 var as = arguments, l = as.length, r = [];
484 for(var i = 0; i < l; i++){
486 if(a instanceof Array){
488 }else if(a.length !== undefined && !a.substr){
489 r = r.concat(Array.prototype.slice.call(a, 0));
498 * Escapes the passed string for use in a regular expression
499 * @param {String} str
502 escapeRe : function(s) {
503 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
507 callback : function(cb, scope, args, delay){
508 if(typeof cb == "function"){
510 cb.defer(delay, scope, args || []);
512 cb.apply(scope, args || []);
518 * Return the dom node for the passed string (id), dom node, or Roo.Element
519 * @param {String/HTMLElement/Roo.Element} el
520 * @return HTMLElement
522 getDom : function(el){
526 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
530 * Shorthand for {@link Roo.ComponentMgr#get}
532 * @return Roo.Component
534 getCmp : function(id){
535 return Roo.ComponentMgr.get(id);
538 num : function(v, defaultValue){
539 if(typeof v != 'number'){
545 destroy : function(){
546 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
550 as.removeAllListeners();
554 if(typeof as.purgeListeners == 'function'){
557 if(typeof as.destroy == 'function'){
564 // inpired by a similar function in mootools library
566 * Returns the type of object that is passed in. If the object passed in is null or undefined it
567 * return false otherwise it returns one of the following values:<ul>
568 * <li><b>string</b>: If the object passed is a string</li>
569 * <li><b>number</b>: If the object passed is a number</li>
570 * <li><b>boolean</b>: If the object passed is a boolean value</li>
571 * <li><b>function</b>: If the object passed is a function reference</li>
572 * <li><b>object</b>: If the object passed is an object</li>
573 * <li><b>array</b>: If the object passed is an array</li>
574 * <li><b>regexp</b>: If the object passed is a regular expression</li>
575 * <li><b>element</b>: If the object passed is a DOM Element</li>
576 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579 * @param {Mixed} object
583 if(o === undefined || o === null){
590 if(t == 'object' && o.nodeName) {
592 case 1: return 'element';
593 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596 if(t == 'object' || t == 'function') {
597 switch(o.constructor) {
598 case Array: return 'array';
599 case RegExp: return 'regexp';
601 if(typeof o.length == 'number' && typeof o.item == 'function') {
609 * Returns true if the passed value is null, undefined or an empty string (optional).
610 * @param {Mixed} value The value to test
611 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614 isEmpty : function(v, allowBlank){
615 return v === null || v === undefined || (!allowBlank ? v === '' : false);
623 isFirefox : isFirefox,
633 isBorderBox : isBorderBox,
635 isWindows : isWindows,
646 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647 * you may want to set this to true.
650 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
655 * Selects a single element as a Roo Element
656 * This is about as close as you can get to jQuery's $('do crazy stuff')
657 * @param {String} selector The selector/xpath query
658 * @param {Node} root (optional) The start of the query (defaults to document).
659 * @return {Roo.Element}
661 selectNode : function(selector, root)
663 var node = Roo.DomQuery.selectNode(selector,root);
664 return node ? Roo.get(node) : new Roo.Element(false);
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
676 "Roo.bootstrap.dash");
679 * Ext JS Library 1.1.1
680 * Copyright(c) 2006-2007, Ext JS, LLC.
682 * Originally Released Under LGPL - original licence link has changed is not relivant.
685 * <script type="text/javascript">
689 // wrappedn so fnCleanup is not in global scope...
691 function fnCleanUp() {
692 var p = Function.prototype;
693 delete p.createSequence;
695 delete p.createDelegate;
696 delete p.createCallback;
697 delete p.createInterceptor;
699 window.detachEvent("onunload", fnCleanUp);
701 window.attachEvent("onunload", fnCleanUp);
708 * These functions are available on every Function object (any JavaScript function).
710 Roo.apply(Function.prototype, {
712 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714 * Will create a function that is bound to those 2 args.
715 * @return {Function} The new function
717 createCallback : function(/*args...*/){
718 // make args available, in function below
719 var args = arguments;
722 return method.apply(window, args);
727 * Creates a delegate (callback) that sets the scope to obj.
728 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729 * Will create a function that is automatically scoped to this.
730 * @param {Object} obj (optional) The object for which the scope is set
731 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733 * if a number the args are inserted at the specified position
734 * @return {Function} The new function
736 createDelegate : function(obj, args, appendArgs){
739 var callArgs = args || arguments;
740 if(appendArgs === true){
741 callArgs = Array.prototype.slice.call(arguments, 0);
742 callArgs = callArgs.concat(args);
743 }else if(typeof appendArgs == "number"){
744 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
748 return method.apply(obj || window, callArgs);
753 * Calls this function after the number of millseconds specified.
754 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755 * @param {Object} obj (optional) The object for which the scope is set
756 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758 * if a number the args are inserted at the specified position
759 * @return {Number} The timeout id that can be used with clearTimeout
761 defer : function(millis, obj, args, appendArgs){
762 var fn = this.createDelegate(obj, args, appendArgs);
764 return setTimeout(fn, millis);
770 * Create a combined function call sequence of the original function + the passed function.
771 * The resulting function returns the results of the original function.
772 * The passed fcn is called with the parameters of the original function
773 * @param {Function} fcn The function to sequence
774 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775 * @return {Function} The new function
777 createSequence : function(fcn, scope){
778 if(typeof fcn != "function"){
783 var retval = method.apply(this || window, arguments);
784 fcn.apply(scope || this || window, arguments);
790 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791 * The resulting function returns the results of the original function.
792 * The passed fcn is called with the parameters of the original function.
794 * @param {Function} fcn The function to call before the original
795 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796 * @return {Function} The new function
798 createInterceptor : function(fcn, scope){
799 if(typeof fcn != "function"){
806 if(fcn.apply(scope || this || window, arguments) === false){
809 return method.apply(this || window, arguments);
815 * Ext JS Library 1.1.1
816 * Copyright(c) 2006-2007, Ext JS, LLC.
818 * Originally Released Under LGPL - original licence link has changed is not relivant.
821 * <script type="text/javascript">
824 Roo.applyIf(String, {
829 * Escapes the passed string for ' and \
830 * @param {String} string The string to escape
831 * @return {String} The escaped string
834 escape : function(string) {
835 return string.replace(/('|\\)/g, "\\$1");
839 * Pads the left side of a string with a specified character. This is especially useful
840 * for normalizing number and date strings. Example usage:
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
845 * @param {String} string The original string
846 * @param {Number} size The total length of the output string
847 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848 * @return {String} The padded string
851 leftPad : function (val, size, ch) {
852 var result = new String(val);
853 if(ch === null || ch === undefined || ch === '') {
856 while (result.length < size) {
857 result = ch + result;
863 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
864 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
870 * @param {String} string The tokenized string to be formatted
871 * @param {String} value1 The value to replace token {0}
872 * @param {String} value2 Etc...
873 * @return {String} The formatted string
876 format : function(format){
877 var args = Array.prototype.slice.call(arguments, 1);
878 return format.replace(/\{(\d+)\}/g, function(m, i){
879 return Roo.util.Format.htmlEncode(args[i]);
885 * Utility function that allows you to easily switch a string between two alternating values. The passed value
886 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
887 * they are already different, the first value passed in is returned. Note that this method returns the new value
888 * but does not change the current string.
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
896 * @param {String} value The value to compare to the current string
897 * @param {String} other The new value to use if the string already equals the first value passed in
898 * @return {String} The new value
901 String.prototype.toggle = function(value, other){
902 return this == value ? other : value;
905 * Ext JS Library 1.1.1
906 * Copyright(c) 2006-2007, Ext JS, LLC.
908 * Originally Released Under LGPL - original licence link has changed is not relivant.
911 * <script type="text/javascript">
917 Roo.applyIf(Number.prototype, {
919 * Checks whether or not the current number is within a desired range. If the number is already within the
920 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921 * exceeded. Note that this method returns the constrained value but does not change the current number.
922 * @param {Number} min The minimum number in the range
923 * @param {Number} max The maximum number in the range
924 * @return {Number} The constrained value if outside the range, otherwise the current value
926 constrain : function(min, max){
927 return Math.min(Math.max(this, min), max);
931 * Ext JS Library 1.1.1
932 * Copyright(c) 2006-2007, Ext JS, LLC.
934 * Originally Released Under LGPL - original licence link has changed is not relivant.
937 * <script type="text/javascript">
942 Roo.applyIf(Array.prototype, {
945 * Checks whether or not the specified object exists in the array.
946 * @param {Object} o The object to check for
947 * @return {Number} The index of o in the array (or -1 if it is not found)
949 indexOf : function(o){
950 for (var i = 0, len = this.length; i < len; i++){
951 if(this[i] == o) { return i; }
957 * Removes the specified object from the array. If the object is not found nothing happens.
958 * @param {Object} o The object to remove
960 remove : function(o){
961 var index = this.indexOf(o);
963 this.splice(index, 1);
967 * Map (JS 1.6 compatibility)
968 * @param {Function} function to call
972 var len = this.length >>> 0;
973 if (typeof fun != "function") {
974 throw new TypeError();
976 var res = new Array(len);
977 var thisp = arguments[1];
978 for (var i = 0; i < len; i++)
981 res[i] = fun.call(thisp, this[i], i, this);
994 * Ext JS Library 1.1.1
995 * Copyright(c) 2006-2007, Ext JS, LLC.
997 * Originally Released Under LGPL - original licence link has changed is not relivant.
1000 * <script type="text/javascript">
1006 * The date parsing and format syntax is a subset of
1007 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008 * supported will provide results equivalent to their PHP versions.
1010 * Following is the list of all currently supported formats:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1015 Format Output Description
1016 ------ ---------- --------------------------------------------------------------
1017 d 10 Day of the month, 2 digits with leading zeros
1018 D Wed A textual representation of a day, three letters
1019 j 10 Day of the month without leading zeros
1020 l Wednesday A full textual representation of the day of the week
1021 S th English ordinal day of month suffix, 2 chars (use with j)
1022 w 3 Numeric representation of the day of the week
1023 z 9 The julian date, or day of the year (0-365)
1024 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025 F January A full textual representation of the month
1026 m 01 Numeric representation of a month, with leading zeros
1027 M Jan Month name abbreviation, three letters
1028 n 1 Numeric representation of a month, without leading zeros
1029 t 31 Number of days in the given month
1030 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1031 Y 2007 A full numeric representation of a year, 4 digits
1032 y 07 A two digit representation of a year
1033 a pm Lowercase Ante meridiem and Post meridiem
1034 A PM Uppercase Ante meridiem and Post meridiem
1035 g 3 12-hour format of an hour without leading zeros
1036 G 15 24-hour format of an hour without leading zeros
1037 h 03 12-hour format of an hour with leading zeros
1038 H 15 24-hour format of an hour with leading zeros
1039 i 05 Minutes with leading zeros
1040 s 01 Seconds, with leading zeros
1041 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1043 T CST Timezone setting of the machine running the code
1044 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1047 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d')); //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1052 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1055 * Here are some standard date/time patterns that you might find helpful. They
1056 * are not part of the source of Date.js, but to use them you can simply copy this
1057 * block of code into any script that is included after Date.js and they will also become
1058 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1061 ISO8601Long:"Y-m-d H:i:s",
1062 ISO8601Short:"Y-m-d",
1064 LongDate: "l, F d, Y",
1065 FullDateTime: "l, F d, Y g:i:s A",
1068 LongTime: "g:i:s A",
1069 SortableDateTime: "Y-m-d\\TH:i:s",
1070 UniversalSortableDateTime: "Y-m-d H:i:sO",
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1083 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084 * They generate precompiled functions from date formats instead of parsing and
1085 * processing the pattern every time you format a date. These functions are available
1086 * on every Date object (any javascript function).
1088 * The original article and download are here:
1089 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096 Returns the number of milliseconds between this date and date
1097 @param {Date} date (optional) Defaults to now
1098 @return {Number} The diff in milliseconds
1099 @member Date getElapsed
1101 Date.prototype.getElapsed = function(date) {
1102 return Math.abs((date || new Date()).getTime()-this.getTime());
1104 // was in date file..
1108 Date.parseFunctions = {count:0};
1110 Date.parseRegexes = [];
1112 Date.formatFunctions = {count:0};
1115 Date.prototype.dateFormat = function(format) {
1116 if (Date.formatFunctions[format] == null) {
1117 Date.createNewFormat(format);
1119 var func = Date.formatFunctions[format];
1120 return this[func]();
1125 * Formats a date given the supplied format string
1126 * @param {String} format The format string
1127 * @return {String} The formatted date
1130 Date.prototype.format = Date.prototype.dateFormat;
1133 Date.createNewFormat = function(format) {
1134 var funcName = "format" + Date.formatFunctions.count++;
1135 Date.formatFunctions[format] = funcName;
1136 var code = "Date.prototype." + funcName + " = function(){return ";
1137 var special = false;
1139 for (var i = 0; i < format.length; ++i) {
1140 ch = format.charAt(i);
1141 if (!special && ch == "\\") {
1146 code += "'" + String.escape(ch) + "' + ";
1149 code += Date.getFormatCode(ch);
1152 /** eval:var:zzzzzzzzzzzzz */
1153 eval(code.substring(0, code.length - 3) + ";}");
1157 Date.getFormatCode = function(character) {
1158 switch (character) {
1160 return "String.leftPad(this.getDate(), 2, '0') + ";
1162 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1164 return "this.getDate() + ";
1166 return "Date.dayNames[this.getDay()] + ";
1168 return "this.getSuffix() + ";
1170 return "this.getDay() + ";
1172 return "this.getDayOfYear() + ";
1174 return "this.getWeekOfYear() + ";
1176 return "Date.monthNames[this.getMonth()] + ";
1178 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1180 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1182 return "(this.getMonth() + 1) + ";
1184 return "this.getDaysInMonth() + ";
1186 return "(this.isLeapYear() ? 1 : 0) + ";
1188 return "this.getFullYear() + ";
1190 return "('' + this.getFullYear()).substring(2, 4) + ";
1192 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1194 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1196 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1198 return "this.getHours() + ";
1200 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1202 return "String.leftPad(this.getHours(), 2, '0') + ";
1204 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1206 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1208 return "this.getGMTOffset() + ";
1210 return "this.getGMTColonOffset() + ";
1212 return "this.getTimezone() + ";
1214 return "(this.getTimezoneOffset() * -60) + ";
1216 return "'" + String.escape(character) + "' + ";
1221 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1223 * the date format that is not specified will default to the current date value for that part. Time parts can also
1224 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1225 * string or the parse operation will fail.
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1240 * @param {String} input The unparsed date as a string
1241 * @param {String} format The format the date is in
1242 * @return {Date} The parsed date
1245 Date.parseDate = function(input, format) {
1246 if (Date.parseFunctions[format] == null) {
1247 Date.createParser(format);
1249 var func = Date.parseFunctions[format];
1250 return Date[func](input);
1256 Date.createParser = function(format) {
1257 var funcName = "parse" + Date.parseFunctions.count++;
1258 var regexNum = Date.parseRegexes.length;
1259 var currentGroup = 1;
1260 Date.parseFunctions[format] = funcName;
1262 var code = "Date." + funcName + " = function(input){\n"
1263 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264 + "var d = new Date();\n"
1265 + "y = d.getFullYear();\n"
1266 + "m = d.getMonth();\n"
1267 + "d = d.getDate();\n"
1268 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270 + "if (results && results.length > 0) {";
1273 var special = false;
1275 for (var i = 0; i < format.length; ++i) {
1276 ch = format.charAt(i);
1277 if (!special && ch == "\\") {
1282 regex += String.escape(ch);
1285 var obj = Date.formatCodeToRegex(ch, currentGroup);
1286 currentGroup += obj.g;
1288 if (obj.g && obj.c) {
1294 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295 + "{v = new Date(y, m, d, h, i, s);}\n"
1296 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297 + "{v = new Date(y, m, d, h, i);}\n"
1298 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299 + "{v = new Date(y, m, d, h);}\n"
1300 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301 + "{v = new Date(y, m, d);}\n"
1302 + "else if (y >= 0 && m >= 0)\n"
1303 + "{v = new Date(y, m);}\n"
1304 + "else if (y >= 0)\n"
1305 + "{v = new Date(y);}\n"
1306 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1311 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312 /** eval:var:zzzzzzzzzzzzz */
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318 switch (character) {
1322 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1325 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326 s:"(\\d{1,2})"}; // day of month without leading zeroes
1329 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330 s:"(\\d{2})"}; // day of month with leading zeroes
1334 s:"(?:" + Date.dayNames.join("|") + ")"};
1338 s:"(?:st|nd|rd|th)"};
1353 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354 s:"(" + Date.monthNames.join("|") + ")"};
1357 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1361 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1365 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1377 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386 c:"if (results[" + currentGroup + "] == 'am') {\n"
1387 + "if (h == 12) { h = 0; }\n"
1388 + "} else { if (h < 12) { h += 12; }}",
1392 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393 + "if (h == 12) { h = 0; }\n"
1394 + "} else { if (h < 12) { h += 12; }}",
1399 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1404 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1408 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1417 "o = results[", currentGroup, "];\n",
1418 "var sn = o.substring(0,1);\n", // get + / - sign
1419 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1424 s:"([+\-]\\d{2,4})"};
1430 "o = results[", currentGroup, "];\n",
1431 "var sn = o.substring(0,1);\n",
1432 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433 "var mn = o.substring(4,6) % 60;\n",
1434 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1441 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1444 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450 s:String.escape(character)};
1455 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456 * @return {String} The abbreviated timezone name (e.g. 'CST')
1458 Date.prototype.getTimezone = function() {
1459 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1466 Date.prototype.getGMTOffset = function() {
1467 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474 * @return {String} 2-characters representing hours and 2-characters representing minutes
1475 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1477 Date.prototype.getGMTColonOffset = function() {
1478 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1481 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 * Get the numeric day number of the year, adjusted for leap year.
1486 * @return {Number} 0 through 364 (365 in leap years)
1488 Date.prototype.getDayOfYear = function() {
1490 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491 for (var i = 0; i < this.getMonth(); ++i) {
1492 num += Date.daysInMonth[i];
1494 return num + this.getDate() - 1;
1498 * Get the string representation of the numeric week number of the year
1499 * (equivalent to the format specifier 'W').
1500 * @return {String} '00' through '52'
1502 Date.prototype.getWeekOfYear = function() {
1503 // Skip to Thursday of this week
1504 var now = this.getDayOfYear() + (4 - this.getDay());
1505 // Find the first Thursday of the year
1506 var jan1 = new Date(this.getFullYear(), 0, 1);
1507 var then = (7 - jan1.getDay() + 4);
1508 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 * Whether or not the current date is in a leap year.
1513 * @return {Boolean} True if the current date is in a leap year, else false
1515 Date.prototype.isLeapYear = function() {
1516 var year = this.getFullYear();
1517 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 * Get the first day of the current month, adjusted for leap year. The returned value
1522 * is the numeric day index within the week (0-6) which can be used in conjunction with
1523 * the {@link #monthNames} array to retrieve the textual day name.
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1529 * @return {Number} The day number (0-6)
1531 Date.prototype.getFirstDayOfMonth = function() {
1532 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533 return (day < 0) ? (day + 7) : day;
1537 * Get the last day of the current month, adjusted for leap year. The returned value
1538 * is the numeric day index within the week (0-6) which can be used in conjunction with
1539 * the {@link #monthNames} array to retrieve the textual day name.
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1545 * @return {Number} The day number (0-6)
1547 Date.prototype.getLastDayOfMonth = function() {
1548 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549 return (day < 0) ? (day + 7) : day;
1554 * Get the first date of this date's month
1557 Date.prototype.getFirstDateOfMonth = function() {
1558 return new Date(this.getFullYear(), this.getMonth(), 1);
1562 * Get the last date of this date's month
1565 Date.prototype.getLastDateOfMonth = function() {
1566 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1569 * Get the number of days in the current month, adjusted for leap year.
1570 * @return {Number} The number of days in the month
1572 Date.prototype.getDaysInMonth = function() {
1573 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574 return Date.daysInMonth[this.getMonth()];
1578 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579 * @return {String} 'st, 'nd', 'rd' or 'th'
1581 Date.prototype.getSuffix = function() {
1582 switch (this.getDate()) {
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1602 * An array of textual month names.
1603 * Override these values for international dates, for example...
1604 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1623 * An array of textual day names.
1624 * Override these values for international dates, for example...
1625 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1641 Date.monthNumbers = {
1656 * Creates and returns a new Date instance with the exact same date value as the called instance.
1657 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658 * variable will also be changed. When the intention is to create a new variable that will not
1659 * modify the original instance, you should create a clone.
1661 * Example of correctly cloning a date:
1664 var orig = new Date('10/1/2006');
1667 document.write(orig); //returns 'Thu Oct 05 2006'!
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1673 document.write(orig); //returns 'Thu Oct 01 2006'
1675 * @return {Date} The new Date instance
1677 Date.prototype.clone = function() {
1678 return new Date(this.getTime());
1682 * Clears any time information from this date
1683 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684 @return {Date} this or the clone
1686 Date.prototype.clearTime = function(clone){
1688 return this.clone().clearTime();
1693 this.setMilliseconds(0);
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700 Date.brokenSetMonth = Date.prototype.setMonth;
1701 Date.prototype.setMonth = function(num){
1703 var n = Math.ceil(-num);
1704 var back_year = Math.ceil(n/12);
1705 var month = (n % 12) ? 12 - n % 12 : 0 ;
1706 this.setFullYear(this.getFullYear() - back_year);
1707 return Date.brokenSetMonth.call(this, month);
1709 return Date.brokenSetMonth.apply(this, arguments);
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1730 /** Date interval constant
1734 /** Date interval constant
1738 /** Date interval constant
1744 * Provides a convenient method of performing basic date arithmetic. This method
1745 * does not modify the Date instance being called - it creates and returns
1746 * a new Date instance containing the resulting date value.
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1763 * @param {String} interval A valid date interval enum value
1764 * @param {Number} value The amount to add to the current date
1765 * @return {Date} The new Date instance
1767 Date.prototype.add = function(interval, value){
1768 var d = this.clone();
1769 if (!interval || value === 0) { return d; }
1770 switch(interval.toLowerCase()){
1772 d.setMilliseconds(this.getMilliseconds() + value);
1775 d.setSeconds(this.getSeconds() + value);
1778 d.setMinutes(this.getMinutes() + value);
1781 d.setHours(this.getHours() + value);
1784 d.setDate(this.getDate() + value);
1787 var day = this.getDate();
1789 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1792 d.setMonth(this.getMonth() + value);
1795 d.setFullYear(this.getFullYear() + value);
1802 * Ext JS Library 1.1.1
1803 * Copyright(c) 2006-2007, Ext JS, LLC.
1805 * Originally Released Under LGPL - original licence link has changed is not relivant.
1808 * <script type="text/javascript">
1812 * @class Roo.lib.Dom
1815 * Dom utils (from YIU afaik)
1820 * Get the view width
1821 * @param {Boolean} full True will get the full document, otherwise it's the view width
1822 * @return {Number} The width
1825 getViewWidth : function(full) {
1826 return full ? this.getDocumentWidth() : this.getViewportWidth();
1829 * Get the view height
1830 * @param {Boolean} full True will get the full document, otherwise it's the view height
1831 * @return {Number} The height
1833 getViewHeight : function(full) {
1834 return full ? this.getDocumentHeight() : this.getViewportHeight();
1837 getDocumentHeight: function() {
1838 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839 return Math.max(scrollHeight, this.getViewportHeight());
1842 getDocumentWidth: function() {
1843 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844 return Math.max(scrollWidth, this.getViewportWidth());
1847 getViewportHeight: function() {
1848 var height = self.innerHeight;
1849 var mode = document.compatMode;
1851 if ((mode || Roo.isIE) && !Roo.isOpera) {
1852 height = (mode == "CSS1Compat") ?
1853 document.documentElement.clientHeight :
1854 document.body.clientHeight;
1860 getViewportWidth: function() {
1861 var width = self.innerWidth;
1862 var mode = document.compatMode;
1864 if (mode || Roo.isIE) {
1865 width = (mode == "CSS1Compat") ?
1866 document.documentElement.clientWidth :
1867 document.body.clientWidth;
1872 isAncestor : function(p, c) {
1879 if (p.contains && !Roo.isSafari) {
1880 return p.contains(c);
1881 } else if (p.compareDocumentPosition) {
1882 return !!(p.compareDocumentPosition(c) & 16);
1884 var parent = c.parentNode;
1889 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1892 parent = parent.parentNode;
1898 getRegion : function(el) {
1899 return Roo.lib.Region.getRegion(el);
1902 getY : function(el) {
1903 return this.getXY(el)[1];
1906 getX : function(el) {
1907 return this.getXY(el)[0];
1910 getXY : function(el) {
1911 var p, pe, b, scroll, bd = document.body;
1912 el = Roo.getDom(el);
1913 var fly = Roo.lib.AnimBase.fly;
1914 if (el.getBoundingClientRect) {
1915 b = el.getBoundingClientRect();
1916 scroll = fly(document).getScroll();
1917 return [b.left + scroll.left, b.top + scroll.top];
1923 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945 if (p != el && pe.getStyle('overflow') != 'visible') {
1953 if (Roo.isSafari && hasAbsolute) {
1958 if (Roo.isGecko && !hasAbsolute) {
1960 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965 while (p && p != bd) {
1966 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1978 setXY : function(el, xy) {
1979 el = Roo.fly(el, '_setXY');
1981 var pts = el.translatePoints(xy);
1982 if (xy[0] !== false) {
1983 el.dom.style.left = pts.left + "px";
1985 if (xy[1] !== false) {
1986 el.dom.style.top = pts.top + "px";
1990 setX : function(el, x) {
1991 this.setXY(el, [x, false]);
1994 setY : function(el, y) {
1995 this.setXY(el, [false, y]);
1999 * Portions of this file are based on pieces of Yahoo User Interface Library
2000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001 * YUI licensed under the BSD License:
2002 * http://developer.yahoo.net/yui/license.txt
2003 * <script type="text/javascript">
2007 Roo.lib.Event = function() {
2008 var loadComplete = false;
2010 var unloadListeners = [];
2012 var onAvailStack = [];
2014 var lastError = null;
2027 startInterval: function() {
2028 if (!this._interval) {
2030 var callback = function() {
2031 self._tryPreloadAttach();
2033 this._interval = setInterval(callback, this.POLL_INTERVAL);
2038 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039 onAvailStack.push({ id: p_id,
2042 override: p_override,
2043 checkReady: false });
2045 retryCount = this.POLL_RETRYS;
2046 this.startInterval();
2050 addListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2056 if ("unload" == eventName) {
2057 unloadListeners[unloadListeners.length] =
2058 [el, eventName, fn];
2062 var wrappedFn = function(e) {
2063 return fn(Roo.lib.Event.getEvent(e));
2066 var li = [el, eventName, fn, wrappedFn];
2068 var index = listeners.length;
2069 listeners[index] = li;
2071 this.doAdd(el, eventName, wrappedFn, false);
2077 removeListener: function(el, eventName, fn) {
2080 el = Roo.getDom(el);
2083 return this.purgeElement(el, false, eventName);
2087 if ("unload" == eventName) {
2089 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090 var li = unloadListeners[i];
2093 li[1] == eventName &&
2095 unloadListeners.splice(i, 1);
2103 var cacheItem = null;
2106 var index = arguments[3];
2108 if ("undefined" == typeof index) {
2109 index = this._getCacheIndex(el, eventName, fn);
2113 cacheItem = listeners[index];
2116 if (!el || !cacheItem) {
2120 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2122 delete listeners[index][this.WFN];
2123 delete listeners[index][this.FN];
2124 listeners.splice(index, 1);
2131 getTarget: function(ev, resolveTextNode) {
2132 ev = ev.browserEvent || ev;
2133 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2134 var t = ev.target || ev.srcElement;
2135 return this.resolveTextNode(t);
2139 resolveTextNode: function(node) {
2140 if (Roo.isSafari && node && 3 == node.nodeType) {
2141 return node.parentNode;
2148 getPageX: function(ev) {
2149 ev = ev.browserEvent || ev;
2150 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 if (!x && 0 !== x) {
2153 x = ev.clientX || 0;
2156 x += this.getScroll()[1];
2164 getPageY: function(ev) {
2165 ev = ev.browserEvent || ev;
2166 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2168 if (!y && 0 !== y) {
2169 y = ev.clientY || 0;
2172 y += this.getScroll()[0];
2181 getXY: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 return [this.getPageX(ev), this.getPageY(ev)];
2188 getRelatedTarget: function(ev) {
2189 ev = ev.browserEvent || ev;
2190 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2191 var t = ev.relatedTarget;
2193 if (ev.type == "mouseout") {
2195 } else if (ev.type == "mouseover") {
2200 return this.resolveTextNode(t);
2204 getTime: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2208 var t = new Date().getTime();
2212 this.lastError = ex;
2221 stopEvent: function(ev) {
2222 this.stopPropagation(ev);
2223 this.preventDefault(ev);
2227 stopPropagation: function(ev) {
2228 ev = ev.browserEvent || ev;
2229 if (ev.stopPropagation) {
2230 ev.stopPropagation();
2232 ev.cancelBubble = true;
2237 preventDefault: function(ev) {
2238 ev = ev.browserEvent || ev;
2239 if(ev.preventDefault) {
2240 ev.preventDefault();
2242 ev.returnValue = false;
2247 getEvent: function(e) {
2248 var ev = e || window.event;
2250 var c = this.getEvent.caller;
2252 ev = c.arguments[0];
2253 if (ev && Event == ev.constructor) {
2263 getCharCode: function(ev) {
2264 ev = ev.browserEvent || ev;
2265 return ev.charCode || ev.keyCode || 0;
2269 _getCacheIndex: function(el, eventName, fn) {
2270 for (var i = 0,len = listeners.length; i < len; ++i) {
2271 var li = listeners[i];
2273 li[this.FN] == fn &&
2274 li[this.EL] == el &&
2275 li[this.TYPE] == eventName) {
2287 getEl: function(id) {
2288 return document.getElementById(id);
2292 clearCache: function() {
2296 _load: function(e) {
2297 loadComplete = true;
2298 var EU = Roo.lib.Event;
2302 EU.doRemove(window, "load", EU._load);
2307 _tryPreloadAttach: function() {
2316 var tryAgain = !loadComplete;
2318 tryAgain = (retryCount > 0);
2323 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324 var item = onAvailStack[i];
2326 var el = this.getEl(item.id);
2329 if (!item.checkReady ||
2332 (document && document.body)) {
2335 if (item.override) {
2336 if (item.override === true) {
2339 scope = item.override;
2342 item.fn.call(scope, item.obj);
2343 onAvailStack[i] = null;
2346 notAvail.push(item);
2351 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355 this.startInterval();
2357 clearInterval(this._interval);
2358 this._interval = null;
2361 this.locked = false;
2368 purgeElement: function(el, recurse, eventName) {
2369 var elListeners = this.getListeners(el, eventName);
2371 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372 var l = elListeners[i];
2373 this.removeListener(el, l.type, l.fn);
2377 if (recurse && el && el.childNodes) {
2378 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379 this.purgeElement(el.childNodes[i], recurse, eventName);
2385 getListeners: function(el, eventName) {
2386 var results = [], searchLists;
2388 searchLists = [listeners, unloadListeners];
2389 } else if (eventName == "unload") {
2390 searchLists = [unloadListeners];
2392 searchLists = [listeners];
2395 for (var j = 0; j < searchLists.length; ++j) {
2396 var searchList = searchLists[j];
2397 if (searchList && searchList.length > 0) {
2398 for (var i = 0,len = searchList.length; i < len; ++i) {
2399 var l = searchList[i];
2400 if (l && l[this.EL] === el &&
2401 (!eventName || eventName === l[this.TYPE])) {
2406 adjust: l[this.ADJ_SCOPE],
2414 return (results.length) ? results : null;
2418 _unload: function(e) {
2420 var EU = Roo.lib.Event, i, j, l, len, index;
2422 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423 l = unloadListeners[i];
2426 if (l[EU.ADJ_SCOPE]) {
2427 if (l[EU.ADJ_SCOPE] === true) {
2430 scope = l[EU.ADJ_SCOPE];
2433 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434 unloadListeners[i] = null;
2440 unloadListeners = null;
2442 if (listeners && listeners.length > 0) {
2443 j = listeners.length;
2446 l = listeners[index];
2448 EU.removeListener(l[EU.EL], l[EU.TYPE],
2458 EU.doRemove(window, "unload", EU._unload);
2463 getScroll: function() {
2464 var dd = document.documentElement, db = document.body;
2465 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466 return [dd.scrollTop, dd.scrollLeft];
2468 return [db.scrollTop, db.scrollLeft];
2475 doAdd: function () {
2476 if (window.addEventListener) {
2477 return function(el, eventName, fn, capture) {
2478 el.addEventListener(eventName, fn, (capture));
2480 } else if (window.attachEvent) {
2481 return function(el, eventName, fn, capture) {
2482 el.attachEvent("on" + eventName, fn);
2491 doRemove: function() {
2492 if (window.removeEventListener) {
2493 return function (el, eventName, fn, capture) {
2494 el.removeEventListener(eventName, fn, (capture));
2496 } else if (window.detachEvent) {
2497 return function (el, eventName, fn) {
2498 el.detachEvent("on" + eventName, fn);
2510 var E = Roo.lib.Event;
2511 E.on = E.addListener;
2512 E.un = E.removeListener;
2514 if (document && document.body) {
2517 E.doAdd(window, "load", E._load);
2519 E.doAdd(window, "unload", E._unload);
2520 E._tryPreloadAttach();
2524 * Portions of this file are based on pieces of Yahoo User Interface Library
2525 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526 * YUI licensed under the BSD License:
2527 * http://developer.yahoo.net/yui/license.txt
2528 * <script type="text/javascript">
2534 * @class Roo.lib.Ajax
2541 request : function(method, uri, cb, data, options) {
2543 var hs = options.headers;
2546 if(hs.hasOwnProperty(h)){
2547 this.initHeader(h, hs[h], false);
2551 if(options.xmlData){
2552 this.initHeader('Content-Type', 'text/xml', false);
2554 data = options.xmlData;
2558 return this.asyncRequest(method, uri, cb, data);
2561 serializeForm : function(form) {
2562 if(typeof form == 'string') {
2563 form = (document.getElementById(form) || document.forms[form]);
2566 var el, name, val, disabled, data = '', hasSubmit = false;
2567 for (var i = 0; i < form.elements.length; i++) {
2568 el = form.elements[i];
2569 disabled = form.elements[i].disabled;
2570 name = form.elements[i].name;
2571 val = form.elements[i].value;
2573 if (!disabled && name){
2577 case 'select-multiple':
2578 for (var j = 0; j < el.options.length; j++) {
2579 if (el.options[j].selected) {
2581 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2592 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2605 if(hasSubmit == false) {
2606 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2616 data = data.substr(0, data.length - 1);
2624 useDefaultHeader:true,
2626 defaultPostHeader:'application/x-www-form-urlencoded',
2628 useDefaultXhrHeader:true,
2630 defaultXhrHeader:'XMLHttpRequest',
2632 hasDefaultHeaders:true,
2644 setProgId:function(id)
2646 this.activeX.unshift(id);
2649 setDefaultPostHeader:function(b)
2651 this.useDefaultHeader = b;
2654 setDefaultXhrHeader:function(b)
2656 this.useDefaultXhrHeader = b;
2659 setPollingInterval:function(i)
2661 if (typeof i == 'number' && isFinite(i)) {
2662 this.pollInterval = i;
2666 createXhrObject:function(transactionId)
2672 http = new XMLHttpRequest();
2674 obj = { conn:http, tId:transactionId };
2678 for (var i = 0; i < this.activeX.length; ++i) {
2682 http = new ActiveXObject(this.activeX[i]);
2684 obj = { conn:http, tId:transactionId };
2697 getConnectionObject:function()
2700 var tId = this.transactionId;
2704 o = this.createXhrObject(tId);
2706 this.transactionId++;
2717 asyncRequest:function(method, uri, callback, postData)
2719 var o = this.getConnectionObject();
2725 o.conn.open(method, uri, true);
2727 if (this.useDefaultXhrHeader) {
2728 if (!this.defaultHeaders['X-Requested-With']) {
2729 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733 if(postData && this.useDefaultHeader){
2734 this.initHeader('Content-Type', this.defaultPostHeader);
2737 if (this.hasDefaultHeaders || this.hasHeaders) {
2741 this.handleReadyState(o, callback);
2742 o.conn.send(postData || null);
2748 handleReadyState:function(o, callback)
2752 if (callback && callback.timeout) {
2754 this.timeout[o.tId] = window.setTimeout(function() {
2755 oConn.abort(o, callback, true);
2756 }, callback.timeout);
2759 this.poll[o.tId] = window.setInterval(
2761 if (o.conn && o.conn.readyState == 4) {
2762 window.clearInterval(oConn.poll[o.tId]);
2763 delete oConn.poll[o.tId];
2765 if(callback && callback.timeout) {
2766 window.clearTimeout(oConn.timeout[o.tId]);
2767 delete oConn.timeout[o.tId];
2770 oConn.handleTransactionResponse(o, callback);
2773 , this.pollInterval);
2776 handleTransactionResponse:function(o, callback, isAbort)
2780 this.releaseObject(o);
2784 var httpStatus, responseObject;
2788 if (o.conn.status !== undefined && o.conn.status != 0) {
2789 httpStatus = o.conn.status;
2801 if (httpStatus >= 200 && httpStatus < 300) {
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.success) {
2804 if (!callback.scope) {
2805 callback.success(responseObject);
2810 callback.success.apply(callback.scope, [responseObject]);
2815 switch (httpStatus) {
2823 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824 if (callback.failure) {
2825 if (!callback.scope) {
2826 callback.failure(responseObject);
2829 callback.failure.apply(callback.scope, [responseObject]);
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.failure) {
2836 if (!callback.scope) {
2837 callback.failure(responseObject);
2840 callback.failure.apply(callback.scope, [responseObject]);
2846 this.releaseObject(o);
2847 responseObject = null;
2850 createResponseObject:function(o, callbackArg)
2857 var headerStr = o.conn.getAllResponseHeaders();
2858 var header = headerStr.split('\n');
2859 for (var i = 0; i < header.length; i++) {
2860 var delimitPos = header[i].indexOf(':');
2861 if (delimitPos != -1) {
2862 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2870 obj.status = o.conn.status;
2871 obj.statusText = o.conn.statusText;
2872 obj.getResponseHeader = headerObj;
2873 obj.getAllResponseHeaders = headerStr;
2874 obj.responseText = o.conn.responseText;
2875 obj.responseXML = o.conn.responseXML;
2877 if (typeof callbackArg !== undefined) {
2878 obj.argument = callbackArg;
2884 createExceptionObject:function(tId, callbackArg, isAbort)
2887 var COMM_ERROR = 'communication failure';
2888 var ABORT_CODE = -1;
2889 var ABORT_ERROR = 'transaction aborted';
2895 obj.status = ABORT_CODE;
2896 obj.statusText = ABORT_ERROR;
2899 obj.status = COMM_CODE;
2900 obj.statusText = COMM_ERROR;
2904 obj.argument = callbackArg;
2910 initHeader:function(label, value, isDefault)
2912 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2914 if (headerObj[label] === undefined) {
2915 headerObj[label] = value;
2920 headerObj[label] = value + "," + headerObj[label];
2924 this.hasDefaultHeaders = true;
2927 this.hasHeaders = true;
2932 setHeader:function(o)
2934 if (this.hasDefaultHeaders) {
2935 for (var prop in this.defaultHeaders) {
2936 if (this.defaultHeaders.hasOwnProperty(prop)) {
2937 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2942 if (this.hasHeaders) {
2943 for (var prop in this.headers) {
2944 if (this.headers.hasOwnProperty(prop)) {
2945 o.conn.setRequestHeader(prop, this.headers[prop]);
2949 this.hasHeaders = false;
2953 resetDefaultHeaders:function() {
2954 delete this.defaultHeaders;
2955 this.defaultHeaders = {};
2956 this.hasDefaultHeaders = false;
2959 abort:function(o, callback, isTimeout)
2961 if(this.isCallInProgress(o)) {
2963 window.clearInterval(this.poll[o.tId]);
2964 delete this.poll[o.tId];
2966 delete this.timeout[o.tId];
2969 this.handleTransactionResponse(o, callback, true);
2979 isCallInProgress:function(o)
2982 return o.conn.readyState != 4 && o.conn.readyState != 0;
2991 releaseObject:function(o)
3000 'MSXML2.XMLHTTP.3.0',
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3016 Roo.lib.Region = function(t, r, b, l) {
3026 Roo.lib.Region.prototype = {
3027 contains : function(region) {
3028 return ( region.left >= this.left &&
3029 region.right <= this.right &&
3030 region.top >= this.top &&
3031 region.bottom <= this.bottom );
3035 getArea : function() {
3036 return ( (this.bottom - this.top) * (this.right - this.left) );
3039 intersect : function(region) {
3040 var t = Math.max(this.top, region.top);
3041 var r = Math.min(this.right, region.right);
3042 var b = Math.min(this.bottom, region.bottom);
3043 var l = Math.max(this.left, region.left);
3045 if (b >= t && r >= l) {
3046 return new Roo.lib.Region(t, r, b, l);
3051 union : function(region) {
3052 var t = Math.min(this.top, region.top);
3053 var r = Math.max(this.right, region.right);
3054 var b = Math.max(this.bottom, region.bottom);
3055 var l = Math.min(this.left, region.left);
3057 return new Roo.lib.Region(t, r, b, l);
3060 adjust : function(t, l, b, r) {
3069 Roo.lib.Region.getRegion = function(el) {
3070 var p = Roo.lib.Dom.getXY(el);
3073 var r = p[0] + el.offsetWidth;
3074 var b = p[1] + el.offsetHeight;
3077 return new Roo.lib.Region(t, r, b, l);
3080 * Portions of this file are based on pieces of Yahoo User Interface Library
3081 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082 * YUI licensed under the BSD License:
3083 * http://developer.yahoo.net/yui/license.txt
3084 * <script type="text/javascript">
3087 //@@dep Roo.lib.Region
3090 Roo.lib.Point = function(x, y) {
3091 if (x instanceof Array) {
3095 this.x = this.right = this.left = this[0] = x;
3096 this.y = this.top = this.bottom = this[1] = y;
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3101 * Portions of this file are based on pieces of Yahoo User Interface Library
3102 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103 * YUI licensed under the BSD License:
3104 * http://developer.yahoo.net/yui/license.txt
3105 * <script type="text/javascript">
3112 scroll : function(el, args, duration, easing, cb, scope) {
3113 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3116 motion : function(el, args, duration, easing, cb, scope) {
3117 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3120 color : function(el, args, duration, easing, cb, scope) {
3121 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3124 run : function(el, args, duration, easing, cb, scope, type) {
3125 type = type || Roo.lib.AnimBase;
3126 if (typeof easing == "string") {
3127 easing = Roo.lib.Easing[easing];
3129 var anim = new type(el, args, duration, easing);
3130 anim.animateX(function() {
3131 Roo.callback(cb, scope);
3137 * Portions of this file are based on pieces of Yahoo User Interface Library
3138 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139 * YUI licensed under the BSD License:
3140 * http://developer.yahoo.net/yui/license.txt
3141 * <script type="text/javascript">
3149 if (!libFlyweight) {
3150 libFlyweight = new Roo.Element.Flyweight();
3152 libFlyweight.dom = el;
3153 return libFlyweight;
3156 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3162 this.init(el, attributes, duration, method);
3166 Roo.lib.AnimBase.fly = fly;
3170 Roo.lib.AnimBase.prototype = {
3172 toString: function() {
3173 var el = this.getEl();
3174 var id = el.id || el.tagName;
3175 return ("Anim " + id);
3179 noNegatives: /width|height|opacity|padding/i,
3180 offsetAttribute: /^((width|height)|(top|left))$/,
3181 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3182 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186 doMethod: function(attr, start, end) {
3187 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191 setAttribute: function(attr, val, unit) {
3192 if (this.patterns.noNegatives.test(attr)) {
3193 val = (val > 0) ? val : 0;
3196 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200 getAttribute: function(attr) {
3201 var el = this.getEl();
3202 var val = fly(el).getStyle(attr);
3204 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205 return parseFloat(val);
3208 var a = this.patterns.offsetAttribute.exec(attr) || [];
3209 var pos = !!( a[3] );
3210 var box = !!( a[2] );
3213 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3223 getDefaultUnit: function(attr) {
3224 if (this.patterns.defaultUnit.test(attr)) {
3231 animateX : function(callback, scope) {
3232 var f = function() {
3233 this.onComplete.removeListener(f);
3234 if (typeof callback == "function") {
3235 callback.call(scope || this, this);
3238 this.onComplete.addListener(f, this);
3243 setRuntimeAttribute: function(attr) {
3246 var attributes = this.attributes;
3248 this.runtimeAttributes[attr] = {};
3250 var isset = function(prop) {
3251 return (typeof prop !== 'undefined');
3254 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3261 if (isset(attributes[attr]['to'])) {
3262 end = attributes[attr]['to'];
3263 } else if (isset(attributes[attr]['by'])) {
3264 if (start.constructor == Array) {
3266 for (var i = 0, len = start.length; i < len; ++i) {
3267 end[i] = start[i] + attributes[attr]['by'][i];
3270 end = start + attributes[attr]['by'];
3274 this.runtimeAttributes[attr].start = start;
3275 this.runtimeAttributes[attr].end = end;
3278 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282 init: function(el, attributes, duration, method) {
3284 var isAnimated = false;
3287 var startTime = null;
3290 var actualFrames = 0;
3293 el = Roo.getDom(el);
3296 this.attributes = attributes || {};
3299 this.duration = duration || 1;
3302 this.method = method || Roo.lib.Easing.easeNone;
3305 this.useSeconds = true;
3308 this.currentFrame = 0;
3311 this.totalFrames = Roo.lib.AnimMgr.fps;
3314 this.getEl = function() {
3319 this.isAnimated = function() {
3324 this.getStartTime = function() {
3328 this.runtimeAttributes = {};
3331 this.animate = function() {
3332 if (this.isAnimated()) {
3336 this.currentFrame = 0;
3338 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3340 Roo.lib.AnimMgr.registerElement(this);
3344 this.stop = function(finish) {
3346 this.currentFrame = this.totalFrames;
3347 this._onTween.fire();
3349 Roo.lib.AnimMgr.stop(this);
3352 var onStart = function() {
3353 this.onStart.fire();
3355 this.runtimeAttributes = {};
3356 for (var attr in this.attributes) {
3357 this.setRuntimeAttribute(attr);
3362 startTime = new Date();
3366 var onTween = function() {
3368 duration: new Date() - this.getStartTime(),
3369 currentFrame: this.currentFrame
3372 data.toString = function() {
3374 'duration: ' + data.duration +
3375 ', currentFrame: ' + data.currentFrame
3379 this.onTween.fire(data);
3381 var runtimeAttributes = this.runtimeAttributes;
3383 for (var attr in runtimeAttributes) {
3384 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3390 var onComplete = function() {
3391 var actual_duration = (new Date() - startTime) / 1000 ;
3394 duration: actual_duration,
3395 frames: actualFrames,
3396 fps: actualFrames / actual_duration
3399 data.toString = function() {
3401 'duration: ' + data.duration +
3402 ', frames: ' + data.frames +
3403 ', fps: ' + data.fps
3409 this.onComplete.fire(data);
3413 this._onStart = new Roo.util.Event(this);
3414 this.onStart = new Roo.util.Event(this);
3415 this.onTween = new Roo.util.Event(this);
3416 this._onTween = new Roo.util.Event(this);
3417 this.onComplete = new Roo.util.Event(this);
3418 this._onComplete = new Roo.util.Event(this);
3419 this._onStart.addListener(onStart);
3420 this._onTween.addListener(onTween);
3421 this._onComplete.addListener(onComplete);
3426 * Portions of this file are based on pieces of Yahoo User Interface Library
3427 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428 * YUI licensed under the BSD License:
3429 * http://developer.yahoo.net/yui/license.txt
3430 * <script type="text/javascript">
3434 Roo.lib.AnimMgr = new function() {
3451 this.registerElement = function(tween) {
3452 queue[queue.length] = tween;
3454 tween._onStart.fire();
3459 this.unRegister = function(tween, index) {
3460 tween._onComplete.fire();
3461 index = index || getIndex(tween);
3463 queue.splice(index, 1);
3467 if (tweenCount <= 0) {
3473 this.start = function() {
3474 if (thread === null) {
3475 thread = setInterval(this.run, this.delay);
3480 this.stop = function(tween) {
3482 clearInterval(thread);
3484 for (var i = 0, len = queue.length; i < len; ++i) {
3485 if (queue[0].isAnimated()) {
3486 this.unRegister(queue[0], 0);
3495 this.unRegister(tween);
3500 this.run = function() {
3501 for (var i = 0, len = queue.length; i < len; ++i) {
3502 var tween = queue[i];
3503 if (!tween || !tween.isAnimated()) {
3507 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3509 tween.currentFrame += 1;
3511 if (tween.useSeconds) {
3512 correctFrame(tween);
3514 tween._onTween.fire();
3517 Roo.lib.AnimMgr.stop(tween, i);
3522 var getIndex = function(anim) {
3523 for (var i = 0, len = queue.length; i < len; ++i) {
3524 if (queue[i] == anim) {
3532 var correctFrame = function(tween) {
3533 var frames = tween.totalFrames;
3534 var frame = tween.currentFrame;
3535 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536 var elapsed = (new Date() - tween.getStartTime());
3539 if (elapsed < tween.duration * 1000) {
3540 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3542 tweak = frames - (frame + 1);
3544 if (tweak > 0 && isFinite(tweak)) {
3545 if (tween.currentFrame + tweak >= frames) {
3546 tweak = frames - (frame + 1);
3549 tween.currentFrame += tweak;
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3562 Roo.lib.Bezier = new function() {
3564 this.getPosition = function(points, t) {
3565 var n = points.length;
3568 for (var i = 0; i < n; ++i) {
3569 tmp[i] = [points[i][0], points[i][1]];
3572 for (var j = 1; j < n; ++j) {
3573 for (i = 0; i < n - j; ++i) {
3574 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579 return [ tmp[0][0], tmp[0][1] ];
3583 * Portions of this file are based on pieces of Yahoo User Interface Library
3584 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585 * YUI licensed under the BSD License:
3586 * http://developer.yahoo.net/yui/license.txt
3587 * <script type="text/javascript">
3592 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3596 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3598 var fly = Roo.lib.AnimBase.fly;
3600 var superclass = Y.ColorAnim.superclass;
3601 var proto = Y.ColorAnim.prototype;
3603 proto.toString = function() {
3604 var el = this.getEl();
3605 var id = el.id || el.tagName;
3606 return ("ColorAnim " + id);
3609 proto.patterns.color = /color$/i;
3610 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3616 proto.parseColor = function(s) {
3617 if (s.length == 3) {
3621 var c = this.patterns.hex.exec(s);
3622 if (c && c.length == 4) {
3623 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3626 c = this.patterns.rgb.exec(s);
3627 if (c && c.length == 4) {
3628 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3631 c = this.patterns.hex3.exec(s);
3632 if (c && c.length == 4) {
3633 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3638 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639 proto.getAttribute = function(attr) {
3640 var el = this.getEl();
3641 if (this.patterns.color.test(attr)) {
3642 var val = fly(el).getStyle(attr);
3644 if (this.patterns.transparent.test(val)) {
3645 var parent = el.parentNode;
3646 val = fly(parent).getStyle(attr);
3648 while (parent && this.patterns.transparent.test(val)) {
3649 parent = parent.parentNode;
3650 val = fly(parent).getStyle(attr);
3651 if (parent.tagName.toUpperCase() == 'HTML') {
3657 val = superclass.getAttribute.call(this, attr);
3662 proto.getAttribute = function(attr) {
3663 var el = this.getEl();
3664 if (this.patterns.color.test(attr)) {
3665 var val = fly(el).getStyle(attr);
3667 if (this.patterns.transparent.test(val)) {
3668 var parent = el.parentNode;
3669 val = fly(parent).getStyle(attr);
3671 while (parent && this.patterns.transparent.test(val)) {
3672 parent = parent.parentNode;
3673 val = fly(parent).getStyle(attr);
3674 if (parent.tagName.toUpperCase() == 'HTML') {
3680 val = superclass.getAttribute.call(this, attr);
3686 proto.doMethod = function(attr, start, end) {
3689 if (this.patterns.color.test(attr)) {
3691 for (var i = 0, len = start.length; i < len; ++i) {
3692 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3695 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3698 val = superclass.doMethod.call(this, attr, start, end);
3704 proto.setRuntimeAttribute = function(attr) {
3705 superclass.setRuntimeAttribute.call(this, attr);
3707 if (this.patterns.color.test(attr)) {
3708 var attributes = this.attributes;
3709 var start = this.parseColor(this.runtimeAttributes[attr].start);
3710 var end = this.parseColor(this.runtimeAttributes[attr].end);
3712 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713 end = this.parseColor(attributes[attr].by);
3715 for (var i = 0, len = start.length; i < len; ++i) {
3716 end[i] = start[i] + end[i];
3720 this.runtimeAttributes[attr].start = start;
3721 this.runtimeAttributes[attr].end = end;
3727 * Portions of this file are based on pieces of Yahoo User Interface Library
3728 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729 * YUI licensed under the BSD License:
3730 * http://developer.yahoo.net/yui/license.txt
3731 * <script type="text/javascript">
3737 easeNone: function (t, b, c, d) {
3738 return c * t / d + b;
3742 easeIn: function (t, b, c, d) {
3743 return c * (t /= d) * t + b;
3747 easeOut: function (t, b, c, d) {
3748 return -c * (t /= d) * (t - 2) + b;
3752 easeBoth: function (t, b, c, d) {
3753 if ((t /= d / 2) < 1) {
3754 return c / 2 * t * t + b;
3757 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761 easeInStrong: function (t, b, c, d) {
3762 return c * (t /= d) * t * t * t + b;
3766 easeOutStrong: function (t, b, c, d) {
3767 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771 easeBothStrong: function (t, b, c, d) {
3772 if ((t /= d / 2) < 1) {
3773 return c / 2 * t * t * t * t + b;
3776 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3781 elasticIn: function (t, b, c, d, a, p) {
3785 if ((t /= d) == 1) {
3792 if (!a || a < Math.abs(c)) {
3797 var s = p / (2 * Math.PI) * Math.asin(c / a);
3800 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804 elasticOut: function (t, b, c, d, a, p) {
3808 if ((t /= d) == 1) {
3815 if (!a || a < Math.abs(c)) {
3820 var s = p / (2 * Math.PI) * Math.asin(c / a);
3823 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827 elasticBoth: function (t, b, c, d, a, p) {
3832 if ((t /= d / 2) == 2) {
3840 if (!a || a < Math.abs(c)) {
3845 var s = p / (2 * Math.PI) * Math.asin(c / a);
3849 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3852 return a * Math.pow(2, -10 * (t -= 1)) *
3853 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3858 backIn: function (t, b, c, d, s) {
3859 if (typeof s == 'undefined') {
3862 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866 backOut: function (t, b, c, d, s) {
3867 if (typeof s == 'undefined') {
3870 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874 backBoth: function (t, b, c, d, s) {
3875 if (typeof s == 'undefined') {
3879 if ((t /= d / 2 ) < 1) {
3880 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3882 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886 bounceIn: function (t, b, c, d) {
3887 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891 bounceOut: function (t, b, c, d) {
3892 if ((t /= d) < (1 / 2.75)) {
3893 return c * (7.5625 * t * t) + b;
3894 } else if (t < (2 / 2.75)) {
3895 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896 } else if (t < (2.5 / 2.75)) {
3897 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3899 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903 bounceBoth: function (t, b, c, d) {
3905 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3907 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3910 * Portions of this file are based on pieces of Yahoo User Interface Library
3911 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912 * YUI licensed under the BSD License:
3913 * http://developer.yahoo.net/yui/license.txt
3914 * <script type="text/javascript">
3918 Roo.lib.Motion = function(el, attributes, duration, method) {
3920 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928 var superclass = Y.Motion.superclass;
3929 var proto = Y.Motion.prototype;
3931 proto.toString = function() {
3932 var el = this.getEl();
3933 var id = el.id || el.tagName;
3934 return ("Motion " + id);
3937 proto.patterns.points = /^points$/i;
3939 proto.setAttribute = function(attr, val, unit) {
3940 if (this.patterns.points.test(attr)) {
3941 unit = unit || 'px';
3942 superclass.setAttribute.call(this, 'left', val[0], unit);
3943 superclass.setAttribute.call(this, 'top', val[1], unit);
3945 superclass.setAttribute.call(this, attr, val, unit);
3949 proto.getAttribute = function(attr) {
3950 if (this.patterns.points.test(attr)) {
3952 superclass.getAttribute.call(this, 'left'),
3953 superclass.getAttribute.call(this, 'top')
3956 val = superclass.getAttribute.call(this, attr);
3962 proto.doMethod = function(attr, start, end) {
3965 if (this.patterns.points.test(attr)) {
3966 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3969 val = superclass.doMethod.call(this, attr, start, end);
3974 proto.setRuntimeAttribute = function(attr) {
3975 if (this.patterns.points.test(attr)) {
3976 var el = this.getEl();
3977 var attributes = this.attributes;
3979 var control = attributes['points']['control'] || [];
3983 if (control.length > 0 && !(control[0] instanceof Array)) {
3984 control = [control];
3987 for (i = 0,len = control.length; i < len; ++i) {
3988 tmp[i] = control[i];
3993 Roo.fly(el).position();
3995 if (isset(attributes['points']['from'])) {
3996 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3999 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4002 start = this.getAttribute('points');
4005 if (isset(attributes['points']['to'])) {
4006 end = translateValues.call(this, attributes['points']['to'], start);
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 for (i = 0,len = control.length; i < len; ++i) {
4010 control[i] = translateValues.call(this, control[i], start);
4014 } else if (isset(attributes['points']['by'])) {
4015 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4017 for (i = 0,len = control.length; i < len; ++i) {
4018 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022 this.runtimeAttributes[attr] = [start];
4024 if (control.length > 0) {
4025 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4028 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4031 superclass.setRuntimeAttribute.call(this, attr);
4035 var translateValues = function(val, start) {
4036 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4042 var isset = function(prop) {
4043 return (typeof prop !== 'undefined');
4047 * Portions of this file are based on pieces of Yahoo User Interface Library
4048 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049 * YUI licensed under the BSD License:
4050 * http://developer.yahoo.net/yui/license.txt
4051 * <script type="text/javascript">
4055 Roo.lib.Scroll = function(el, attributes, duration, method) {
4057 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065 var superclass = Y.Scroll.superclass;
4066 var proto = Y.Scroll.prototype;
4068 proto.toString = function() {
4069 var el = this.getEl();
4070 var id = el.id || el.tagName;
4071 return ("Scroll " + id);
4074 proto.doMethod = function(attr, start, end) {
4077 if (attr == 'scroll') {
4079 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084 val = superclass.doMethod.call(this, attr, start, end);
4089 proto.getAttribute = function(attr) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 val = [ el.scrollLeft, el.scrollTop ];
4096 val = superclass.getAttribute.call(this, attr);
4102 proto.setAttribute = function(attr, val, unit) {
4103 var el = this.getEl();
4105 if (attr == 'scroll') {
4106 el.scrollLeft = val[0];
4107 el.scrollTop = val[1];
4109 superclass.setAttribute.call(this, attr, val, unit);
4115 * Ext JS Library 1.1.1
4116 * Copyright(c) 2006-2007, Ext JS, LLC.
4118 * Originally Released Under LGPL - original licence link has changed is not relivant.
4121 * <script type="text/javascript">
4125 // nasty IE9 hack - what a pile of crap that is..
4127 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128 Range.prototype.createContextualFragment = function (html) {
4129 var doc = window.document;
4130 var container = doc.createElement("div");
4131 container.innerHTML = html;
4132 var frag = doc.createDocumentFragment(), n;
4133 while ((n = container.firstChild)) {
4134 frag.appendChild(n);
4141 * @class Roo.DomHelper
4142 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4146 Roo.DomHelper = function(){
4147 var tempTableEl = null;
4148 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149 var tableRe = /^table|tbody|tr|td$/i;
4151 // build as innerHTML where available
4153 var createHtml = function(o){
4154 if(typeof o == 'string'){
4163 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164 if(attr == "style"){
4166 if(typeof s == "function"){
4169 if(typeof s == "string"){
4170 b += ' style="' + s + '"';
4171 }else if(typeof s == "object"){
4174 if(typeof s[key] != "function"){
4175 b += key + ":" + s[key] + ";";
4182 b += ' class="' + o["cls"] + '"';
4183 }else if(attr == "htmlFor"){
4184 b += ' for="' + o["htmlFor"] + '"';
4186 b += " " + attr + '="' + o[attr] + '"';
4190 if(emptyTags.test(o.tag)){
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 b += createHtml(cn[i], b);
4202 b += createHtml(cn, b);
4208 b += "</" + o.tag + ">";
4215 var createDom = function(o, parentNode){
4217 // defininition craeted..
4219 if (o.ns && o.ns != 'html') {
4221 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222 xmlns[o.ns] = o.xmlns;
4225 if (typeof(xmlns[o.ns]) == 'undefined') {
4226 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4232 if (typeof(o) == 'string') {
4233 return parentNode.appendChild(document.createTextNode(o));
4235 o.tag = o.tag || div;
4236 if (o.ns && Roo.isIE) {
4238 o.tag = o.ns + ':' + o.tag;
4241 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4242 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4245 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4246 attr == "style" || typeof o[attr] == "function") { continue; }
4248 if(attr=="cls" && Roo.isIE){
4249 el.className = o["cls"];
4251 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4257 Roo.DomHelper.applyStyles(el, o.style);
4258 var cn = o.children || o.cn;
4260 //http://bugs.kde.org/show_bug.cgi?id=71506
4261 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262 for(var i = 0, len = cn.length; i < len; i++) {
4263 createDom(cn[i], el);
4270 el.innerHTML = o.html;
4273 parentNode.appendChild(el);
4278 var ieTable = function(depth, s, h, e){
4279 tempTableEl.innerHTML = [s, h, e].join('');
4280 var i = -1, el = tempTableEl;
4287 // kill repeat to save bytes
4291 tbe = '</tbody>'+te,
4297 * Nasty code for IE's broken table implementation
4299 var insertIntoTable = function(tag, where, el, html){
4301 tempTableEl = document.createElement('div');
4306 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4309 if(where == 'beforebegin'){
4313 before = el.nextSibling;
4316 node = ieTable(4, trs, html, tre);
4318 else if(tag == 'tr'){
4319 if(where == 'beforebegin'){
4322 node = ieTable(3, tbs, html, tbe);
4323 } else if(where == 'afterend'){
4324 before = el.nextSibling;
4326 node = ieTable(3, tbs, html, tbe);
4327 } else{ // INTO a TR
4328 if(where == 'afterbegin'){
4329 before = el.firstChild;
4331 node = ieTable(4, trs, html, tre);
4333 } else if(tag == 'tbody'){
4334 if(where == 'beforebegin'){
4337 node = ieTable(2, ts, html, te);
4338 } else if(where == 'afterend'){
4339 before = el.nextSibling;
4341 node = ieTable(2, ts, html, te);
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(3, tbs, html, tbe);
4349 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4352 if(where == 'afterbegin'){
4353 before = el.firstChild;
4355 node = ieTable(2, ts, html, te);
4357 el.insertBefore(node, before);
4362 /** True to force the use of DOM instead of html fragments @type Boolean */
4366 * Returns the markup for the passed Element(s) config
4367 * @param {Object} o The Dom object spec (and children)
4370 markup : function(o){
4371 return createHtml(o);
4375 * Applies a style specification to an element
4376 * @param {String/HTMLElement} el The element to apply styles to
4377 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378 * a function which returns such a specification.
4380 applyStyles : function(el, styles){
4383 if(typeof styles == "string"){
4384 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4386 while ((matches = re.exec(styles)) != null){
4387 el.setStyle(matches[1], matches[2]);
4389 }else if (typeof styles == "object"){
4390 for (var style in styles){
4391 el.setStyle(style, styles[style]);
4393 }else if (typeof styles == "function"){
4394 Roo.DomHelper.applyStyles(el, styles.call());
4400 * Inserts an HTML fragment into the Dom
4401 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402 * @param {HTMLElement} el The context element
4403 * @param {String} html The HTML fragmenet
4404 * @return {HTMLElement} The new node
4406 insertHtml : function(where, el, html){
4407 where = where.toLowerCase();
4408 if(el.insertAdjacentHTML){
4409 if(tableRe.test(el.tagName)){
4411 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4417 el.insertAdjacentHTML('BeforeBegin', html);
4418 return el.previousSibling;
4420 el.insertAdjacentHTML('AfterBegin', html);
4421 return el.firstChild;
4423 el.insertAdjacentHTML('BeforeEnd', html);
4424 return el.lastChild;
4426 el.insertAdjacentHTML('AfterEnd', html);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4431 var range = el.ownerDocument.createRange();
4435 range.setStartBefore(el);
4436 frag = range.createContextualFragment(html);
4437 el.parentNode.insertBefore(frag, el);
4438 return el.previousSibling;
4441 range.setStartBefore(el.firstChild);
4442 frag = range.createContextualFragment(html);
4443 el.insertBefore(frag, el.firstChild);
4444 return el.firstChild;
4446 el.innerHTML = html;
4447 return el.firstChild;
4451 range.setStartAfter(el.lastChild);
4452 frag = range.createContextualFragment(html);
4453 el.appendChild(frag);
4454 return el.lastChild;
4456 el.innerHTML = html;
4457 return el.lastChild;
4460 range.setStartAfter(el);
4461 frag = range.createContextualFragment(html);
4462 el.parentNode.insertBefore(frag, el.nextSibling);
4463 return el.nextSibling;
4465 throw 'Illegal insertion point -> "' + where + '"';
4469 * Creates new Dom element(s) and inserts them before el
4470 * @param {String/HTMLElement/Element} el The context element
4471 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473 * @return {HTMLElement/Roo.Element} The new node
4475 insertBefore : function(el, o, returnElement){
4476 return this.doInsert(el, o, returnElement, "beforeBegin");
4480 * Creates new Dom element(s) and inserts them after el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object} o The Dom object spec (and children)
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 insertAfter : function(el, o, returnElement){
4487 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491 * Creates new Dom element(s) and inserts them as the first child of el
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 insertFirst : function(el, o, returnElement){
4498 return this.doInsert(el, o, returnElement, "afterBegin");
4502 doInsert : function(el, o, returnElement, pos, sibling){
4503 el = Roo.getDom(el);
4505 if(this.useDom || o.ns){
4506 newNode = createDom(o, null);
4507 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4509 var html = createHtml(o);
4510 newNode = this.insertHtml(pos, el, html);
4512 return returnElement ? Roo.get(newNode, true) : newNode;
4516 * Creates new Dom element(s) and appends them to el
4517 * @param {String/HTMLElement/Element} el The context element
4518 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520 * @return {HTMLElement/Roo.Element} The new node
4522 append : function(el, o, returnElement){
4523 el = Roo.getDom(el);
4525 if(this.useDom || o.ns){
4526 newNode = createDom(o, null);
4527 el.appendChild(newNode);
4529 var html = createHtml(o);
4530 newNode = this.insertHtml("beforeEnd", el, html);
4532 return returnElement ? Roo.get(newNode, true) : newNode;
4536 * Creates new Dom element(s) and overwrites the contents of el with them
4537 * @param {String/HTMLElement/Element} el The context element
4538 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540 * @return {HTMLElement/Roo.Element} The new node
4542 overwrite : function(el, o, returnElement){
4543 el = Roo.getDom(el);
4546 while (el.childNodes.length) {
4547 el.removeChild(el.firstChild);
4551 el.innerHTML = createHtml(o);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Creates a new Roo.DomHelper.Template from the Dom object spec
4559 * @param {Object} o The Dom object spec (and children)
4560 * @return {Roo.DomHelper.Template} The new template
4562 createTemplate : function(o){
4563 var html = createHtml(o);
4564 return new Roo.Template(html);
4570 * Ext JS Library 1.1.1
4571 * Copyright(c) 2006-2007, Ext JS, LLC.
4573 * Originally Released Under LGPL - original licence link has changed is not relivant.
4576 * <script type="text/javascript">
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4585 var t = new Roo.Template({
4586 html : '<div name="{id}">' +
4587 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4589 myformat: function (value, allValues) {
4590 return 'XX' + value;
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4595 * For more information see this blog post with examples:
4596 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597 - Create Elements using DOM, HTML fragments and Templates</a>.
4599 * @param {Object} cfg - Configuration object.
4601 Roo.Template = function(cfg){
4603 if(cfg instanceof Array){
4605 }else if(arguments.length > 1){
4606 cfg = Array.prototype.join.call(arguments, "");
4610 if (typeof(cfg) == 'object') {
4621 Roo.Template.prototype = {
4624 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4625 * it should be fixed so that template is observable...
4629 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633 * Returns an HTML fragment of this template with the specified values applied.
4634 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4635 * @return {String} The HTML fragment
4637 applyTemplate : function(values){
4641 return this.compiled(values);
4643 var useF = this.disableFormats !== true;
4644 var fm = Roo.util.Format, tpl = this;
4645 var fn = function(m, name, format, args){
4647 if(format.substr(0, 5) == "this."){
4648 return tpl.call(format.substr(5), values[name], values);
4651 // quoted values are required for strings in compiled templates,
4652 // but for non compiled we need to strip them
4653 // quoted reversed for jsmin
4654 var re = /^\s*['"](.*)["']\s*$/;
4655 args = args.split(',');
4656 for(var i = 0, len = args.length; i < len; i++){
4657 args[i] = args[i].replace(re, "$1");
4659 args = [values[name]].concat(args);
4661 args = [values[name]];
4663 return fm[format].apply(fm, args);
4666 return values[name] !== undefined ? values[name] : "";
4669 return this.html.replace(this.re, fn);
4687 this.loading = true;
4688 this.compiled = false;
4690 var cx = new Roo.data.Connection();
4694 success : function (response) {
4696 _t.html = response.responseText;
4700 failure : function(response) {
4701 Roo.log("Template failed to load from " + _t.url);
4708 * Sets the HTML used as the template and optionally compiles it.
4709 * @param {String} html
4710 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711 * @return {Roo.Template} this
4713 set : function(html, compile){
4715 this.compiled = null;
4723 * True to disable format functions (defaults to false)
4726 disableFormats : false,
4729 * The regular expression used to match template variables
4733 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4736 * Compiles the template into an internal function, eliminating the RegEx overhead.
4737 * @return {Roo.Template} this
4739 compile : function(){
4740 var fm = Roo.util.Format;
4741 var useF = this.disableFormats !== true;
4742 var sep = Roo.isGecko ? "+" : ",";
4743 var fn = function(m, name, format, args){
4745 args = args ? ',' + args : "";
4746 if(format.substr(0, 5) != "this."){
4747 format = "fm." + format + '(';
4749 format = 'this.call("'+ format.substr(5) + '", ';
4753 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4755 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4758 // branched to use + in gecko and [].join() in others
4760 body = "this.compiled = function(values){ return '" +
4761 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4764 body = ["this.compiled = function(values){ return ['"];
4765 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766 body.push("'].join('');};");
4767 body = body.join('');
4777 // private function used to call members
4778 call : function(fnName, value, allValues){
4779 return this[fnName](value, allValues);
4783 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784 * @param {String/HTMLElement/Roo.Element} el The context element
4785 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4786 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787 * @return {HTMLElement/Roo.Element} The new node or Element
4789 insertFirst: function(el, values, returnElement){
4790 return this.doInsert('afterBegin', el, values, returnElement);
4794 * Applies the supplied values to the template and inserts the new node(s) before el.
4795 * @param {String/HTMLElement/Roo.Element} el The context element
4796 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4797 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798 * @return {HTMLElement/Roo.Element} The new node or Element
4800 insertBefore: function(el, values, returnElement){
4801 return this.doInsert('beforeBegin', el, values, returnElement);
4805 * Applies the supplied values to the template and inserts the new node(s) after el.
4806 * @param {String/HTMLElement/Roo.Element} el The context element
4807 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4808 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809 * @return {HTMLElement/Roo.Element} The new node or Element
4811 insertAfter : function(el, values, returnElement){
4812 return this.doInsert('afterEnd', el, values, returnElement);
4816 * Applies the supplied values to the template and appends the new node(s) to el.
4817 * @param {String/HTMLElement/Roo.Element} el The context element
4818 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4819 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820 * @return {HTMLElement/Roo.Element} The new node or Element
4822 append : function(el, values, returnElement){
4823 return this.doInsert('beforeEnd', el, values, returnElement);
4826 doInsert : function(where, el, values, returnEl){
4827 el = Roo.getDom(el);
4828 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829 return returnEl ? Roo.get(newNode, true) : newNode;
4833 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834 * @param {String/HTMLElement/Roo.Element} el The context element
4835 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4836 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837 * @return {HTMLElement/Roo.Element} The new node or Element
4839 overwrite : function(el, values, returnElement){
4840 el = Roo.getDom(el);
4841 el.innerHTML = this.applyTemplate(values);
4842 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846 * Alias for {@link #applyTemplate}
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4852 Roo.DomHelper.Template = Roo.Template;
4855 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856 * @param {String/HTMLElement} el A DOM element or its id
4857 * @returns {Roo.Template} The created template
4860 Roo.Template.from = function(el){
4861 el = Roo.getDom(el);
4862 return new Roo.Template(el.value || el.innerHTML);
4865 * Ext JS Library 1.1.1
4866 * Copyright(c) 2006-2007, Ext JS, LLC.
4868 * Originally Released Under LGPL - original licence link has changed is not relivant.
4871 * <script type="text/javascript">
4876 * This is code is also distributed under MIT license for use
4877 * with jQuery and prototype JavaScript libraries.
4880 * @class Roo.DomQuery
4881 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4883 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4886 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4888 <h4>Element Selectors:</h4>
4890 <li> <b>*</b> any element</li>
4891 <li> <b>E</b> an element with the tag E</li>
4892 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4900 <li> <b>E[foo]</b> has an attribute "foo"</li>
4901 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4908 <h4>Pseudo Classes:</h4>
4910 <li> <b>E:first-child</b> E is the first child of its parent</li>
4911 <li> <b>E:last-child</b> E is the last child of its parent</li>
4912 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4913 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915 <li> <b>E:only-child</b> E is the only child of its parent</li>
4916 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4917 <li> <b>E:first</b> the first E in the resultset</li>
4918 <li> <b>E:last</b> the last E in the resultset</li>
4919 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4929 <h4>CSS Value Selectors:</h4>
4931 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 Roo.DomQuery = function(){
4941 var cache = {}, simpleCache = {}, valueCache = {};
4942 var nonSpace = /\S/;
4943 var trimRe = /^\s+|\s+$/g;
4944 var tplRe = /\{(\d+)\}/g;
4945 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946 var tagTokenRe = /^(#)?([\w-\*]+)/;
4947 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4949 function child(p, index){
4951 var n = p.firstChild;
4953 if(n.nodeType == 1){
4964 while((n = n.nextSibling) && n.nodeType != 1);
4969 while((n = n.previousSibling) && n.nodeType != 1);
4973 function children(d){
4974 var n = d.firstChild, ni = -1;
4976 var nx = n.nextSibling;
4977 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4987 function byClassName(c, a, v){
4991 var r = [], ri = -1, cn;
4992 for(var i = 0, ci; ci = c[i]; i++){
4993 if((' '+ci.className+' ').indexOf(v) != -1){
5000 function attrValue(n, attr){
5001 if(!n.tagName && typeof n.length != "undefined"){
5010 if(attr == "class" || attr == "className"){
5013 return n.getAttribute(attr) || n[attr];
5017 function getNodes(ns, mode, tagName){
5018 var result = [], ri = -1, cs;
5022 tagName = tagName || "*";
5023 if(typeof ns.getElementsByTagName != "undefined"){
5027 for(var i = 0, ni; ni = ns[i]; i++){
5028 cs = ni.getElementsByTagName(tagName);
5029 for(var j = 0, ci; ci = cs[j]; j++){
5033 }else if(mode == "/" || mode == ">"){
5034 var utag = tagName.toUpperCase();
5035 for(var i = 0, ni, cn; ni = ns[i]; i++){
5036 cn = ni.children || ni.childNodes;
5037 for(var j = 0, cj; cj = cn[j]; j++){
5038 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5043 }else if(mode == "+"){
5044 var utag = tagName.toUpperCase();
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && n.nodeType != 1);
5047 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051 }else if(mode == "~"){
5052 for(var i = 0, n; n = ns[i]; i++){
5053 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5062 function concat(a, b){
5066 for(var i = 0, l = b.length; i < l; i++){
5072 function byTag(cs, tagName){
5073 if(cs.tagName || cs == document){
5079 var r = [], ri = -1;
5080 tagName = tagName.toLowerCase();
5081 for(var i = 0, ci; ci = cs[i]; i++){
5082 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089 function byId(cs, attr, id){
5090 if(cs.tagName || cs == document){
5096 var r = [], ri = -1;
5097 for(var i = 0,ci; ci = cs[i]; i++){
5098 if(ci && ci.id == id){
5106 function byAttribute(cs, attr, value, op, custom){
5107 var r = [], ri = -1, st = custom=="{";
5108 var f = Roo.DomQuery.operators[op];
5109 for(var i = 0, ci; ci = cs[i]; i++){
5112 a = Roo.DomQuery.getStyle(ci, attr);
5114 else if(attr == "class" || attr == "className"){
5116 }else if(attr == "for"){
5118 }else if(attr == "href"){
5119 a = ci.getAttribute("href", 2);
5121 a = ci.getAttribute(attr);
5123 if((f && f(a, value)) || (!f && a)){
5130 function byPseudo(cs, name, value){
5131 return Roo.DomQuery.pseudos[name](cs, value);
5134 // This is for IE MSXML which does not support expandos.
5135 // IE runs the same speed using setAttribute, however FF slows way down
5136 // and Safari completely fails so they need to continue to use expandos.
5137 var isIE = window.ActiveXObject ? true : false;
5139 // this eval is stop the compressor from
5140 // renaming the variable to something shorter
5142 /** eval:var:batch */
5147 function nodupIEXml(cs){
5149 cs[0].setAttribute("_nodup", d);
5151 for(var i = 1, len = cs.length; i < len; i++){
5153 if(!c.getAttribute("_nodup") != d){
5154 c.setAttribute("_nodup", d);
5158 for(var i = 0, len = cs.length; i < len; i++){
5159 cs[i].removeAttribute("_nodup");
5168 var len = cs.length, c, i, r = cs, cj, ri = -1;
5169 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5172 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173 return nodupIEXml(cs);
5177 for(i = 1; c = cs[i]; i++){
5182 for(var j = 0; j < i; j++){
5185 for(j = i+1; cj = cs[j]; j++){
5197 function quickDiffIEXml(c1, c2){
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].setAttribute("_qdiff", d);
5203 for(var i = 0, len = c2.length; i < len; i++){
5204 if(c2[i].getAttribute("_qdiff") != d){
5205 r[r.length] = c2[i];
5208 for(var i = 0, len = c1.length; i < len; i++){
5209 c1[i].removeAttribute("_qdiff");
5214 function quickDiff(c1, c2){
5215 var len1 = c1.length;
5219 if(isIE && c1[0].selectSingleNode){
5220 return quickDiffIEXml(c1, c2);
5223 for(var i = 0; i < len1; i++){
5227 for(var i = 0, len = c2.length; i < len; i++){
5228 if(c2[i]._qdiff != d){
5229 r[r.length] = c2[i];
5235 function quickId(ns, mode, root, id){
5237 var d = root.ownerDocument || root;
5238 return d.getElementById(id);
5240 ns = getNodes(ns, mode, "*");
5241 return byId(ns, null, id);
5245 getStyle : function(el, name){
5246 return Roo.fly(el).getStyle(name);
5249 * Compiles a selector/xpath query into a reusable function. The returned function
5250 * takes one parameter "root" (optional), which is the context node from where the query should start.
5251 * @param {String} selector The selector/xpath query
5252 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253 * @return {Function}
5255 compile : function(path, type){
5256 type = type || "select";
5258 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259 var q = path, mode, lq;
5260 var tk = Roo.DomQuery.matchers;
5261 var tklen = tk.length;
5264 // accept leading mode switch
5265 var lmode = q.match(modeRe);
5266 if(lmode && lmode[1]){
5267 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268 q = q.replace(lmode[1], "");
5270 // strip leading slashes
5271 while(path.substr(0, 1)=="/"){
5272 path = path.substr(1);
5275 while(q && lq != q){
5277 var tm = q.match(tagTokenRe);
5278 if(type == "select"){
5281 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5283 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5285 q = q.replace(tm[0], "");
5286 }else if(q.substr(0, 1) != '@'){
5287 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5292 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5294 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5296 q = q.replace(tm[0], "");
5299 while(!(mm = q.match(modeRe))){
5300 var matched = false;
5301 for(var j = 0; j < tklen; j++){
5303 var m = q.match(t.re);
5305 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5308 q = q.replace(m[0], "");
5313 // prevent infinite loop on bad selector
5315 throw 'Error parsing selector, parsing failed at "' + q + '"';
5319 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320 q = q.replace(mm[1], "");
5323 fn[fn.length] = "return nodup(n);\n}";
5326 * list of variables that need from compression as they are used by eval.
5336 * eval:var:byClassName
5338 * eval:var:byAttribute
5339 * eval:var:attrValue
5347 * Selects a group of elements.
5348 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 select : function(path, root, type){
5353 if(!root || root == document){
5356 if(typeof root == "string"){
5357 root = document.getElementById(root);
5359 var paths = path.split(",");
5361 for(var i = 0, len = paths.length; i < len; i++){
5362 var p = paths[i].replace(trimRe, "");
5364 cache[p] = Roo.DomQuery.compile(p);
5366 throw p + " is not a valid selector";
5369 var result = cache[p](root);
5370 if(result && result != document){
5371 results = results.concat(result);
5374 if(paths.length > 1){
5375 return nodup(results);
5381 * Selects a single element.
5382 * @param {String} selector The selector/xpath query
5383 * @param {Node} root (optional) The start of the query (defaults to document).
5386 selectNode : function(path, root){
5387 return Roo.DomQuery.select(path, root)[0];
5391 * Selects the value of a node, optionally replacing null with the defaultValue.
5392 * @param {String} selector The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5394 * @param {String} defaultValue
5396 selectValue : function(path, root, defaultValue){
5397 path = path.replace(trimRe, "");
5398 if(!valueCache[path]){
5399 valueCache[path] = Roo.DomQuery.compile(path, "select");
5401 var n = valueCache[path](root);
5402 n = n[0] ? n[0] : n;
5403 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408 * Selects the value of a node, parsing integers and floats.
5409 * @param {String} selector The selector/xpath query
5410 * @param {Node} root (optional) The start of the query (defaults to document).
5411 * @param {Number} defaultValue
5414 selectNumber : function(path, root, defaultValue){
5415 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416 return parseFloat(v);
5420 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422 * @param {String} selector The simple selector to test
5425 is : function(el, ss){
5426 if(typeof el == "string"){
5427 el = document.getElementById(el);
5429 var isArray = (el instanceof Array);
5430 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431 return isArray ? (result.length == el.length) : (result.length > 0);
5435 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436 * @param {Array} el An array of elements to filter
5437 * @param {String} selector The simple selector to test
5438 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439 * the selector instead of the ones that match
5442 filter : function(els, ss, nonMatches){
5443 ss = ss.replace(trimRe, "");
5444 if(!simpleCache[ss]){
5445 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5447 var result = simpleCache[ss](els);
5448 return nonMatches ? quickDiff(result, els) : result;
5452 * Collection of matching regular expressions and code snippets.
5456 select: 'n = byClassName(n, null, " {1} ");'
5458 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459 select: 'n = byPseudo(n, "{1}", "{2}");'
5461 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5465 select: 'n = byId(n, null, "{1}");'
5468 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5473 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5477 "=" : function(a, v){
5480 "!=" : function(a, v){
5483 "^=" : function(a, v){
5484 return a && a.substr(0, v.length) == v;
5486 "$=" : function(a, v){
5487 return a && a.substr(a.length-v.length) == v;
5489 "*=" : function(a, v){
5490 return a && a.indexOf(v) !== -1;
5492 "%=" : function(a, v){
5493 return (a % v) == 0;
5495 "|=" : function(a, v){
5496 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5498 "~=" : function(a, v){
5499 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5504 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505 * and the argument (if any) supplied in the selector.
5508 "first-child" : function(c){
5509 var r = [], ri = -1, n;
5510 for(var i = 0, ci; ci = n = c[i]; i++){
5511 while((n = n.previousSibling) && n.nodeType != 1);
5519 "last-child" : function(c){
5520 var r = [], ri = -1, n;
5521 for(var i = 0, ci; ci = n = c[i]; i++){
5522 while((n = n.nextSibling) && n.nodeType != 1);
5530 "nth-child" : function(c, a) {
5531 var r = [], ri = -1;
5532 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534 for(var i = 0, n; n = c[i]; i++){
5535 var pn = n.parentNode;
5536 if (batch != pn._batch) {
5538 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539 if(cn.nodeType == 1){
5546 if (l == 0 || n.nodeIndex == l){
5549 } else if ((n.nodeIndex + l) % f == 0){
5557 "only-child" : function(c){
5558 var r = [], ri = -1;;
5559 for(var i = 0, ci; ci = c[i]; i++){
5560 if(!prev(ci) && !next(ci)){
5567 "empty" : function(c){
5568 var r = [], ri = -1;
5569 for(var i = 0, ci; ci = c[i]; i++){
5570 var cns = ci.childNodes, j = 0, cn, empty = true;
5573 if(cn.nodeType == 1 || cn.nodeType == 3){
5585 "contains" : function(c, v){
5586 var r = [], ri = -1;
5587 for(var i = 0, ci; ci = c[i]; i++){
5588 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595 "nodeValue" : function(c, v){
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(ci.firstChild && ci.firstChild.nodeValue == v){
5605 "checked" : function(c){
5606 var r = [], ri = -1;
5607 for(var i = 0, ci; ci = c[i]; i++){
5608 if(ci.checked == true){
5615 "not" : function(c, ss){
5616 return Roo.DomQuery.filter(c, ss, true);
5619 "odd" : function(c){
5620 return this["nth-child"](c, "odd");
5623 "even" : function(c){
5624 return this["nth-child"](c, "even");
5627 "nth" : function(c, a){
5628 return c[a-1] || [];
5631 "first" : function(c){
5635 "last" : function(c){
5636 return c[c.length-1] || [];
5639 "has" : function(c, ss){
5640 var s = Roo.DomQuery.select;
5641 var r = [], ri = -1;
5642 for(var i = 0, ci; ci = c[i]; i++){
5643 if(s(ss, ci).length > 0){
5650 "next" : function(c, ss){
5651 var is = Roo.DomQuery.is;
5652 var r = [], ri = -1;
5653 for(var i = 0, ci; ci = c[i]; i++){
5662 "prev" : function(c, ss){
5663 var is = Roo.DomQuery.is;
5664 var r = [], ri = -1;
5665 for(var i = 0, ci; ci = c[i]; i++){
5678 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679 * @param {String} path The selector/xpath query
5680 * @param {Node} root (optional) The start of the query (defaults to document).
5685 Roo.query = Roo.DomQuery.select;
5688 * Ext JS Library 1.1.1
5689 * Copyright(c) 2006-2007, Ext JS, LLC.
5691 * Originally Released Under LGPL - original licence link has changed is not relivant.
5694 * <script type="text/javascript">
5698 * @class Roo.util.Observable
5699 * Base class that provides a common interface for publishing events. Subclasses are expected to
5700 * to have a property "events" with all the events defined.<br>
5703 Employee = function(name){
5710 Roo.extend(Employee, Roo.util.Observable);
5712 * @param {Object} config properties to use (incuding events / listeners)
5715 Roo.util.Observable = function(cfg){
5718 this.addEvents(cfg.events || {});
5720 delete cfg.events; // make sure
5723 Roo.apply(this, cfg);
5726 this.on(this.listeners);
5727 delete this.listeners;
5730 Roo.util.Observable.prototype = {
5732 * @cfg {Object} listeners list of events and functions to call for this object,
5736 'click' : function(e) {
5746 * Fires the specified event with the passed parameters (minus the event name).
5747 * @param {String} eventName
5748 * @param {Object...} args Variable number of parameters are passed to handlers
5749 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5751 fireEvent : function(){
5752 var ce = this.events[arguments[0].toLowerCase()];
5753 if(typeof ce == "object"){
5754 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5764 * Appends an event handler to this component
5765 * @param {String} eventName The type of event to listen for
5766 * @param {Function} handler The method the event invokes
5767 * @param {Object} scope (optional) The scope in which to execute the handler
5768 * function. The handler function's "this" context.
5769 * @param {Object} options (optional) An object containing handler configuration
5770 * properties. This may contain any of the following properties:<ul>
5771 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775 * by the specified number of milliseconds. If the event fires again within that time, the original
5776 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5779 * <b>Combining Options</b><br>
5780 * Using the options argument, it is possible to combine different types of listeners:<br>
5782 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5784 el.on('click', this.onClick, this, {
5791 * <b>Attaching multiple handlers in 1 call</b><br>
5792 * The method also allows for a single argument to be passed which is a config object containing properties
5793 * which specify multiple handlers.
5802 fn: this.onMouseOver,
5806 fn: this.onMouseOut,
5812 * Or a shorthand syntax which passes the same scope object to all handlers:
5815 'click': this.onClick,
5816 'mouseover': this.onMouseOver,
5817 'mouseout': this.onMouseOut,
5822 addListener : function(eventName, fn, scope, o){
5823 if(typeof eventName == "object"){
5826 if(this.filterOptRe.test(e)){
5829 if(typeof o[e] == "function"){
5831 this.addListener(e, o[e], o.scope, o);
5833 // individual options
5834 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5839 o = (!o || typeof o == "boolean") ? {} : o;
5840 eventName = eventName.toLowerCase();
5841 var ce = this.events[eventName] || true;
5842 if(typeof ce == "boolean"){
5843 ce = new Roo.util.Event(this, eventName);
5844 this.events[eventName] = ce;
5846 ce.addListener(fn, scope, o);
5850 * Removes a listener
5851 * @param {String} eventName The type of event to listen for
5852 * @param {Function} handler The handler to remove
5853 * @param {Object} scope (optional) The scope (this object) for the handler
5855 removeListener : function(eventName, fn, scope){
5856 var ce = this.events[eventName.toLowerCase()];
5857 if(typeof ce == "object"){
5858 ce.removeListener(fn, scope);
5863 * Removes all listeners for this object
5865 purgeListeners : function(){
5866 for(var evt in this.events){
5867 if(typeof this.events[evt] == "object"){
5868 this.events[evt].clearListeners();
5873 relayEvents : function(o, events){
5874 var createHandler = function(ename){
5876 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5879 for(var i = 0, len = events.length; i < len; i++){
5880 var ename = events[i];
5881 if(!this.events[ename]){ this.events[ename] = true; };
5882 o.on(ename, createHandler(ename), this);
5887 * Used to define events on this Observable
5888 * @param {Object} object The object with the events defined
5890 addEvents : function(o){
5894 Roo.applyIf(this.events, o);
5898 * Checks to see if this object has any listeners for a specified event
5899 * @param {String} eventName The name of the event to check for
5900 * @return {Boolean} True if the event is being listened for, else false
5902 hasListener : function(eventName){
5903 var e = this.events[eventName];
5904 return typeof e == "object" && e.listeners.length > 0;
5908 * Appends an event handler to this element (shorthand for addListener)
5909 * @param {String} eventName The type of event to listen for
5910 * @param {Function} handler The method the event invokes
5911 * @param {Object} scope (optional) The scope in which to execute the handler
5912 * function. The handler function's "this" context.
5913 * @param {Object} options (optional)
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5918 * Removes a listener (shorthand for removeListener)
5919 * @param {String} eventName The type of event to listen for
5920 * @param {Function} handler The handler to remove
5921 * @param {Object} scope (optional) The scope (this object) for the handler
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5927 * Starts capture on the specified Observable. All events will be passed
5928 * to the supplied function with the event name + standard signature of the event
5929 * <b>before</b> the event is fired. If the supplied function returns false,
5930 * the event will not fire.
5931 * @param {Observable} o The Observable to capture
5932 * @param {Function} fn The function to call
5933 * @param {Object} scope (optional) The scope (this object) for the fn
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 * Removes <b>all</b> added captures from the Observable.
5942 * @param {Observable} o The Observable to release
5945 Roo.util.Observable.releaseCapture = function(o){
5946 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5951 var createBuffered = function(h, o, scope){
5952 var task = new Roo.util.DelayedTask();
5954 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958 var createSingle = function(h, e, fn, scope){
5960 e.removeListener(fn, scope);
5961 return h.apply(scope, arguments);
5965 var createDelayed = function(h, o, scope){
5967 var args = Array.prototype.slice.call(arguments, 0);
5968 setTimeout(function(){
5969 h.apply(scope, args);
5974 Roo.util.Event = function(obj, name){
5977 this.listeners = [];
5980 Roo.util.Event.prototype = {
5981 addListener : function(fn, scope, options){
5982 var o = options || {};
5983 scope = scope || this.obj;
5984 if(!this.isListening(fn, scope)){
5985 var l = {fn: fn, scope: scope, options: o};
5988 h = createDelayed(h, o, scope);
5991 h = createSingle(h, this, fn, scope);
5994 h = createBuffered(h, o, scope);
5997 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998 this.listeners.push(l);
6000 this.listeners = this.listeners.slice(0);
6001 this.listeners.push(l);
6006 findListener : function(fn, scope){
6007 scope = scope || this.obj;
6008 var ls = this.listeners;
6009 for(var i = 0, len = ls.length; i < len; i++){
6011 if(l.fn == fn && l.scope == scope){
6018 isListening : function(fn, scope){
6019 return this.findListener(fn, scope) != -1;
6022 removeListener : function(fn, scope){
6024 if((index = this.findListener(fn, scope)) != -1){
6026 this.listeners.splice(index, 1);
6028 this.listeners = this.listeners.slice(0);
6029 this.listeners.splice(index, 1);
6036 clearListeners : function(){
6037 this.listeners = [];
6041 var ls = this.listeners, scope, len = ls.length;
6044 var args = Array.prototype.slice.call(arguments, 0);
6045 for(var i = 0; i < len; i++){
6047 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048 this.firing = false;
6052 this.firing = false;
6059 * Ext JS Library 1.1.1
6060 * Copyright(c) 2006-2007, Ext JS, LLC.
6062 * Originally Released Under LGPL - original licence link has changed is not relivant.
6065 * <script type="text/javascript">
6069 * @class Roo.EventManager
6070 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6071 * several useful events directly.
6072 * See {@link Roo.EventObject} for more details on normalized event objects.
6075 Roo.EventManager = function(){
6076 var docReadyEvent, docReadyProcId, docReadyState = false;
6077 var resizeEvent, resizeTask, textEvent, textSize;
6078 var E = Roo.lib.Event;
6079 var D = Roo.lib.Dom;
6084 var fireDocReady = function(){
6086 docReadyState = true;
6089 clearInterval(docReadyProcId);
6091 if(Roo.isGecko || Roo.isOpera) {
6092 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6095 var defer = document.getElementById("ie-deferred-loader");
6097 defer.onreadystatechange = null;
6098 defer.parentNode.removeChild(defer);
6102 docReadyEvent.fire();
6103 docReadyEvent.clearListeners();
6108 var initDocReady = function(){
6109 docReadyEvent = new Roo.util.Event();
6110 if(Roo.isGecko || Roo.isOpera) {
6111 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6113 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6114 var defer = document.getElementById("ie-deferred-loader");
6115 defer.onreadystatechange = function(){
6116 if(this.readyState == "complete"){
6120 }else if(Roo.isSafari){
6121 docReadyProcId = setInterval(function(){
6122 var rs = document.readyState;
6123 if(rs == "complete") {
6128 // no matter what, make sure it fires on load
6129 E.on(window, "load", fireDocReady);
6132 var createBuffered = function(h, o){
6133 var task = new Roo.util.DelayedTask(h);
6135 // create new event object impl so new events don't wipe out properties
6136 e = new Roo.EventObjectImpl(e);
6137 task.delay(o.buffer, h, null, [e]);
6141 var createSingle = function(h, el, ename, fn){
6143 Roo.EventManager.removeListener(el, ename, fn);
6148 var createDelayed = function(h, o){
6150 // create new event object impl so new events don't wipe out properties
6151 e = new Roo.EventObjectImpl(e);
6152 setTimeout(function(){
6157 var transitionEndVal = false;
6159 var transitionEnd = function()
6161 if (transitionEndVal) {
6162 return transitionEndVal;
6164 var el = document.createElement('div');
6166 var transEndEventNames = {
6167 WebkitTransition : 'webkitTransitionEnd',
6168 MozTransition : 'transitionend',
6169 OTransition : 'oTransitionEnd otransitionend',
6170 transition : 'transitionend'
6173 for (var name in transEndEventNames) {
6174 if (el.style[name] !== undefined) {
6175 transitionEndVal = transEndEventNames[name];
6176 return transitionEndVal ;
6182 var listen = function(element, ename, opt, fn, scope){
6183 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6184 fn = fn || o.fn; scope = scope || o.scope;
6185 var el = Roo.getDom(element);
6189 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6192 if (ename == 'transitionend') {
6193 ename = transitionEnd();
6195 var h = function(e){
6196 e = Roo.EventObject.setEvent(e);
6199 t = e.getTarget(o.delegate, el);
6206 if(o.stopEvent === true){
6209 if(o.preventDefault === true){
6212 if(o.stopPropagation === true){
6213 e.stopPropagation();
6216 if(o.normalized === false){
6220 fn.call(scope || el, e, t, o);
6223 h = createDelayed(h, o);
6226 h = createSingle(h, el, ename, fn);
6229 h = createBuffered(h, o);
6231 fn._handlers = fn._handlers || [];
6234 fn._handlers.push([Roo.id(el), ename, h]);
6239 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6240 el.addEventListener("DOMMouseScroll", h, false);
6241 E.on(window, 'unload', function(){
6242 el.removeEventListener("DOMMouseScroll", h, false);
6245 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6246 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6251 var stopListening = function(el, ename, fn){
6252 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6254 for(var i = 0, len = hds.length; i < len; i++){
6256 if(h[0] == id && h[1] == ename){
6263 E.un(el, ename, hd);
6264 el = Roo.getDom(el);
6265 if(ename == "mousewheel" && el.addEventListener){
6266 el.removeEventListener("DOMMouseScroll", hd, false);
6268 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6269 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6273 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6280 * @scope Roo.EventManager
6285 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6286 * object with a Roo.EventObject
6287 * @param {Function} fn The method the event invokes
6288 * @param {Object} scope An object that becomes the scope of the handler
6289 * @param {boolean} override If true, the obj passed in becomes
6290 * the execution scope of the listener
6291 * @return {Function} The wrapped function
6294 wrap : function(fn, scope, override){
6296 Roo.EventObject.setEvent(e);
6297 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6302 * Appends an event handler to an element (shorthand for addListener)
6303 * @param {String/HTMLElement} element The html element or id to assign the
6304 * @param {String} eventName The type of event to listen for
6305 * @param {Function} handler The method the event invokes
6306 * @param {Object} scope (optional) The scope in which to execute the handler
6307 * function. The handler function's "this" context.
6308 * @param {Object} options (optional) An object containing handler configuration
6309 * properties. This may contain any of the following properties:<ul>
6310 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6311 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6312 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6313 * <li>preventDefault {Boolean} True to prevent the default action</li>
6314 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6315 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6316 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6317 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6318 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6319 * by the specified number of milliseconds. If the event fires again within that time, the original
6320 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6323 * <b>Combining Options</b><br>
6324 * Using the options argument, it is possible to combine different types of listeners:<br>
6326 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6328 el.on('click', this.onClick, this, {
6335 * <b>Attaching multiple handlers in 1 call</b><br>
6336 * The method also allows for a single argument to be passed which is a config object containing properties
6337 * which specify multiple handlers.
6347 fn: this.onMouseOver
6356 * Or a shorthand syntax:<br>
6359 'click' : this.onClick,
6360 'mouseover' : this.onMouseOver,
6361 'mouseout' : this.onMouseOut
6365 addListener : function(element, eventName, fn, scope, options){
6366 if(typeof eventName == "object"){
6372 if(typeof o[e] == "function"){
6374 listen(element, e, o, o[e], o.scope);
6376 // individual options
6377 listen(element, e, o[e]);
6382 return listen(element, eventName, options, fn, scope);
6386 * Removes an event handler
6388 * @param {String/HTMLElement} element The id or html element to remove the
6390 * @param {String} eventName The type of event
6391 * @param {Function} fn
6392 * @return {Boolean} True if a listener was actually removed
6394 removeListener : function(element, eventName, fn){
6395 return stopListening(element, eventName, fn);
6399 * Fires when the document is ready (before onload and before images are loaded). Can be
6400 * accessed shorthanded Roo.onReady().
6401 * @param {Function} fn The method the event invokes
6402 * @param {Object} scope An object that becomes the scope of the handler
6403 * @param {boolean} options
6405 onDocumentReady : function(fn, scope, options){
6406 if(docReadyState){ // if it already fired
6407 docReadyEvent.addListener(fn, scope, options);
6408 docReadyEvent.fire();
6409 docReadyEvent.clearListeners();
6415 docReadyEvent.addListener(fn, scope, options);
6419 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6420 * @param {Function} fn The method the event invokes
6421 * @param {Object} scope An object that becomes the scope of the handler
6422 * @param {boolean} options
6424 onWindowResize : function(fn, scope, options){
6426 resizeEvent = new Roo.util.Event();
6427 resizeTask = new Roo.util.DelayedTask(function(){
6428 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6430 E.on(window, "resize", function(){
6432 resizeTask.delay(50);
6434 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6438 resizeEvent.addListener(fn, scope, options);
6442 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6443 * @param {Function} fn The method the event invokes
6444 * @param {Object} scope An object that becomes the scope of the handler
6445 * @param {boolean} options
6447 onTextResize : function(fn, scope, options){
6449 textEvent = new Roo.util.Event();
6450 var textEl = new Roo.Element(document.createElement('div'));
6451 textEl.dom.className = 'x-text-resize';
6452 textEl.dom.innerHTML = 'X';
6453 textEl.appendTo(document.body);
6454 textSize = textEl.dom.offsetHeight;
6455 setInterval(function(){
6456 if(textEl.dom.offsetHeight != textSize){
6457 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6459 }, this.textResizeInterval);
6461 textEvent.addListener(fn, scope, options);
6465 * Removes the passed window resize listener.
6466 * @param {Function} fn The method the event invokes
6467 * @param {Object} scope The scope of handler
6469 removeResizeListener : function(fn, scope){
6471 resizeEvent.removeListener(fn, scope);
6476 fireResize : function(){
6478 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6482 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6486 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6488 textResizeInterval : 50
6493 * @scopeAlias pub=Roo.EventManager
6497 * Appends an event handler to an element (shorthand for addListener)
6498 * @param {String/HTMLElement} element The html element or id to assign the
6499 * @param {String} eventName The type of event to listen for
6500 * @param {Function} handler The method the event invokes
6501 * @param {Object} scope (optional) The scope in which to execute the handler
6502 * function. The handler function's "this" context.
6503 * @param {Object} options (optional) An object containing handler configuration
6504 * properties. This may contain any of the following properties:<ul>
6505 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6506 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6507 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6508 * <li>preventDefault {Boolean} True to prevent the default action</li>
6509 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6510 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6511 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6512 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6513 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6514 * by the specified number of milliseconds. If the event fires again within that time, the original
6515 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6518 * <b>Combining Options</b><br>
6519 * Using the options argument, it is possible to combine different types of listeners:<br>
6521 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6523 el.on('click', this.onClick, this, {
6530 * <b>Attaching multiple handlers in 1 call</b><br>
6531 * The method also allows for a single argument to be passed which is a config object containing properties
6532 * which specify multiple handlers.
6542 fn: this.onMouseOver
6551 * Or a shorthand syntax:<br>
6554 'click' : this.onClick,
6555 'mouseover' : this.onMouseOver,
6556 'mouseout' : this.onMouseOut
6560 pub.on = pub.addListener;
6561 pub.un = pub.removeListener;
6563 pub.stoppedMouseDownEvent = new Roo.util.Event();
6567 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6568 * @param {Function} fn The method the event invokes
6569 * @param {Object} scope An object that becomes the scope of the handler
6570 * @param {boolean} override If true, the obj passed in becomes
6571 * the execution scope of the listener
6575 Roo.onReady = Roo.EventManager.onDocumentReady;
6577 Roo.onReady(function(){
6578 var bd = Roo.get(document.body);
6583 : Roo.isGecko ? "roo-gecko"
6584 : Roo.isOpera ? "roo-opera"
6585 : Roo.isSafari ? "roo-safari" : ""];
6588 cls.push("roo-mac");
6591 cls.push("roo-linux");
6594 cls.push("roo-ios");
6597 cls.push("roo-touch");
6599 if(Roo.isBorderBox){
6600 cls.push('roo-border-box');
6602 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6603 var p = bd.dom.parentNode;
6605 p.className += ' roo-strict';
6608 bd.addClass(cls.join(' '));
6612 * @class Roo.EventObject
6613 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6614 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6617 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6619 var target = e.getTarget();
6622 var myDiv = Roo.get("myDiv");
6623 myDiv.on("click", handleClick);
6625 Roo.EventManager.on("myDiv", 'click', handleClick);
6626 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6630 Roo.EventObject = function(){
6632 var E = Roo.lib.Event;
6634 // safari keypress events for special keys return bad keycodes
6637 63235 : 39, // right
6640 63276 : 33, // page up
6641 63277 : 34, // page down
6642 63272 : 46, // delete
6647 // normalize button clicks
6648 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6649 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6651 Roo.EventObjectImpl = function(e){
6653 this.setEvent(e.browserEvent || e);
6656 Roo.EventObjectImpl.prototype = {
6658 * Used to fix doc tools.
6659 * @scope Roo.EventObject.prototype
6665 /** The normal browser event */
6666 browserEvent : null,
6667 /** The button pressed in a mouse event */
6669 /** True if the shift key was down during the event */
6671 /** True if the control key was down during the event */
6673 /** True if the alt key was down during the event */
6732 setEvent : function(e){
6733 if(e == this || (e && e.browserEvent)){ // already wrapped
6736 this.browserEvent = e;
6738 // normalize buttons
6739 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6740 if(e.type == 'click' && this.button == -1){
6744 this.shiftKey = e.shiftKey;
6745 // mac metaKey behaves like ctrlKey
6746 this.ctrlKey = e.ctrlKey || e.metaKey;
6747 this.altKey = e.altKey;
6748 // in getKey these will be normalized for the mac
6749 this.keyCode = e.keyCode;
6750 // keyup warnings on firefox.
6751 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6752 // cache the target for the delayed and or buffered events
6753 this.target = E.getTarget(e);
6755 this.xy = E.getXY(e);
6758 this.shiftKey = false;
6759 this.ctrlKey = false;
6760 this.altKey = false;
6770 * Stop the event (preventDefault and stopPropagation)
6772 stopEvent : function(){
6773 if(this.browserEvent){
6774 if(this.browserEvent.type == 'mousedown'){
6775 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6777 E.stopEvent(this.browserEvent);
6782 * Prevents the browsers default handling of the event.
6784 preventDefault : function(){
6785 if(this.browserEvent){
6786 E.preventDefault(this.browserEvent);
6791 isNavKeyPress : function(){
6792 var k = this.keyCode;
6793 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6794 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6797 isSpecialKey : function(){
6798 var k = this.keyCode;
6799 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6800 (k == 16) || (k == 17) ||
6801 (k >= 18 && k <= 20) ||
6802 (k >= 33 && k <= 35) ||
6803 (k >= 36 && k <= 39) ||
6804 (k >= 44 && k <= 45);
6807 * Cancels bubbling of the event.
6809 stopPropagation : function(){
6810 if(this.browserEvent){
6811 if(this.type == 'mousedown'){
6812 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6814 E.stopPropagation(this.browserEvent);
6819 * Gets the key code for the event.
6822 getCharCode : function(){
6823 return this.charCode || this.keyCode;
6827 * Returns a normalized keyCode for the event.
6828 * @return {Number} The key code
6830 getKey : function(){
6831 var k = this.keyCode || this.charCode;
6832 return Roo.isSafari ? (safariKeys[k] || k) : k;
6836 * Gets the x coordinate of the event.
6839 getPageX : function(){
6844 * Gets the y coordinate of the event.
6847 getPageY : function(){
6852 * Gets the time of the event.
6855 getTime : function(){
6856 if(this.browserEvent){
6857 return E.getTime(this.browserEvent);
6863 * Gets the page coordinates of the event.
6864 * @return {Array} The xy values like [x, y]
6871 * Gets the target for the event.
6872 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6873 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6874 search as a number or element (defaults to 10 || document.body)
6875 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6876 * @return {HTMLelement}
6878 getTarget : function(selector, maxDepth, returnEl){
6879 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6882 * Gets the related target.
6883 * @return {HTMLElement}
6885 getRelatedTarget : function(){
6886 if(this.browserEvent){
6887 return E.getRelatedTarget(this.browserEvent);
6893 * Normalizes mouse wheel delta across browsers
6894 * @return {Number} The delta
6896 getWheelDelta : function(){
6897 var e = this.browserEvent;
6899 if(e.wheelDelta){ /* IE/Opera. */
6900 delta = e.wheelDelta/120;
6901 }else if(e.detail){ /* Mozilla case. */
6902 delta = -e.detail/3;
6908 * Returns true if the control, meta, shift or alt key was pressed during this event.
6911 hasModifier : function(){
6912 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6916 * Returns true if the target of this event equals el or is a child of el
6917 * @param {String/HTMLElement/Element} el
6918 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6921 within : function(el, related){
6922 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6923 return t && Roo.fly(el).contains(t);
6926 getPoint : function(){
6927 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6931 return new Roo.EventObjectImpl();
6936 * Ext JS Library 1.1.1
6937 * Copyright(c) 2006-2007, Ext JS, LLC.
6939 * Originally Released Under LGPL - original licence link has changed is not relivant.
6942 * <script type="text/javascript">
6946 // was in Composite Element!??!?!
6949 var D = Roo.lib.Dom;
6950 var E = Roo.lib.Event;
6951 var A = Roo.lib.Anim;
6953 // local style camelizing for speed
6955 var camelRe = /(-[a-z])/gi;
6956 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6957 var view = document.defaultView;
6960 * @class Roo.Element
6961 * Represents an Element in the DOM.<br><br>
6964 var el = Roo.get("my-div");
6967 var el = getEl("my-div");
6969 // or with a DOM element
6970 var el = Roo.get(myDivElement);
6972 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6973 * each call instead of constructing a new one.<br><br>
6974 * <b>Animations</b><br />
6975 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6976 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6978 Option Default Description
6979 --------- -------- ---------------------------------------------
6980 duration .35 The duration of the animation in seconds
6981 easing easeOut The YUI easing method
6982 callback none A function to execute when the anim completes
6983 scope this The scope (this) of the callback function
6985 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6986 * manipulate the animation. Here's an example:
6988 var el = Roo.get("my-div");
6993 // default animation
6994 el.setWidth(100, true);
6996 // animation with some options set
7003 // using the "anim" property to get the Anim object
7009 el.setWidth(100, opt);
7011 if(opt.anim.isAnimated()){
7015 * <b> Composite (Collections of) Elements</b><br />
7016 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7017 * @constructor Create a new Element directly.
7018 * @param {String/HTMLElement} element
7019 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7021 Roo.Element = function(element, forceNew){
7022 var dom = typeof element == "string" ?
7023 document.getElementById(element) : element;
7024 if(!dom){ // invalid id/element
7028 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7029 return Roo.Element.cache[id];
7039 * The DOM element ID
7042 this.id = id || Roo.id(dom);
7045 var El = Roo.Element;
7049 * The element's default display mode (defaults to "")
7052 originalDisplay : "",
7056 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7062 * Sets the element's visibility mode. When setVisible() is called it
7063 * will use this to determine whether to set the visibility or the display property.
7064 * @param visMode Element.VISIBILITY or Element.DISPLAY
7065 * @return {Roo.Element} this
7067 setVisibilityMode : function(visMode){
7068 this.visibilityMode = visMode;
7072 * Convenience method for setVisibilityMode(Element.DISPLAY)
7073 * @param {String} display (optional) What to set display to when visible
7074 * @return {Roo.Element} this
7076 enableDisplayMode : function(display){
7077 this.setVisibilityMode(El.DISPLAY);
7078 if(typeof display != "undefined") { this.originalDisplay = display; }
7083 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7084 * @param {String} selector The simple selector to test
7085 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7086 search as a number or element (defaults to 10 || document.body)
7087 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7088 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7090 findParent : function(simpleSelector, maxDepth, returnEl){
7091 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7092 maxDepth = maxDepth || 50;
7093 if(typeof maxDepth != "number"){
7094 stopEl = Roo.getDom(maxDepth);
7097 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7098 if(dq.is(p, simpleSelector)){
7099 return returnEl ? Roo.get(p) : p;
7109 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7110 * @param {String} selector The simple selector to test
7111 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7112 search as a number or element (defaults to 10 || document.body)
7113 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7114 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7116 findParentNode : function(simpleSelector, maxDepth, returnEl){
7117 var p = Roo.fly(this.dom.parentNode, '_internal');
7118 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7122 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7123 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7124 * @param {String} selector The simple selector to test
7125 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7126 search as a number or element (defaults to 10 || document.body)
7127 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7129 up : function(simpleSelector, maxDepth){
7130 return this.findParentNode(simpleSelector, maxDepth, true);
7136 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7137 * @param {String} selector The simple selector to test
7138 * @return {Boolean} True if this element matches the selector, else false
7140 is : function(simpleSelector){
7141 return Roo.DomQuery.is(this.dom, simpleSelector);
7145 * Perform animation on this element.
7146 * @param {Object} args The YUI animation control args
7147 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7148 * @param {Function} onComplete (optional) Function to call when animation completes
7149 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7150 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7151 * @return {Roo.Element} this
7153 animate : function(args, duration, onComplete, easing, animType){
7154 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7159 * @private Internal animation call
7161 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7162 animType = animType || 'run';
7164 var anim = Roo.lib.Anim[animType](
7166 (opt.duration || defaultDur) || .35,
7167 (opt.easing || defaultEase) || 'easeOut',
7169 Roo.callback(cb, this);
7170 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7178 // private legacy anim prep
7179 preanim : function(a, i){
7180 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7184 * Removes worthless text nodes
7185 * @param {Boolean} forceReclean (optional) By default the element
7186 * keeps track if it has been cleaned already so
7187 * you can call this over and over. However, if you update the element and
7188 * need to force a reclean, you can pass true.
7190 clean : function(forceReclean){
7191 if(this.isCleaned && forceReclean !== true){
7195 var d = this.dom, n = d.firstChild, ni = -1;
7197 var nx = n.nextSibling;
7198 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7205 this.isCleaned = true;
7210 calcOffsetsTo : function(el){
7213 var restorePos = false;
7214 if(el.getStyle('position') == 'static'){
7215 el.position('relative');
7220 while(op && op != d && op.tagName != 'HTML'){
7223 op = op.offsetParent;
7226 el.position('static');
7232 * Scrolls this element into view within the passed container.
7233 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7234 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7235 * @return {Roo.Element} this
7237 scrollIntoView : function(container, hscroll){
7238 var c = Roo.getDom(container) || document.body;
7241 var o = this.calcOffsetsTo(c),
7244 b = t+el.offsetHeight,
7245 r = l+el.offsetWidth;
7247 var ch = c.clientHeight;
7248 var ct = parseInt(c.scrollTop, 10);
7249 var cl = parseInt(c.scrollLeft, 10);
7251 var cr = cl + c.clientWidth;
7259 if(hscroll !== false){
7263 c.scrollLeft = r-c.clientWidth;
7270 scrollChildIntoView : function(child, hscroll){
7271 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7275 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7276 * the new height may not be available immediately.
7277 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7278 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7279 * @param {Function} onComplete (optional) Function to call when animation completes
7280 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7281 * @return {Roo.Element} this
7283 autoHeight : function(animate, duration, onComplete, easing){
7284 var oldHeight = this.getHeight();
7286 this.setHeight(1); // force clipping
7287 setTimeout(function(){
7288 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7290 this.setHeight(height);
7292 if(typeof onComplete == "function"){
7296 this.setHeight(oldHeight); // restore original height
7297 this.setHeight(height, animate, duration, function(){
7299 if(typeof onComplete == "function") { onComplete(); }
7300 }.createDelegate(this), easing);
7302 }.createDelegate(this), 0);
7307 * Returns true if this element is an ancestor of the passed element
7308 * @param {HTMLElement/String} el The element to check
7309 * @return {Boolean} True if this element is an ancestor of el, else false
7311 contains : function(el){
7312 if(!el){return false;}
7313 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7317 * Checks whether the element is currently visible using both visibility and display properties.
7318 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7319 * @return {Boolean} True if the element is currently visible, else false
7321 isVisible : function(deep) {
7322 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7323 if(deep !== true || !vis){
7326 var p = this.dom.parentNode;
7327 while(p && p.tagName.toLowerCase() != "body"){
7328 if(!Roo.fly(p, '_isVisible').isVisible()){
7337 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7338 * @param {String} selector The CSS selector
7339 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7340 * @return {CompositeElement/CompositeElementLite} The composite element
7342 select : function(selector, unique){
7343 return El.select(selector, unique, this.dom);
7347 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7348 * @param {String} selector The CSS selector
7349 * @return {Array} An array of the matched nodes
7351 query : function(selector, unique){
7352 return Roo.DomQuery.select(selector, this.dom);
7356 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7357 * @param {String} selector The CSS selector
7358 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7359 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7361 child : function(selector, returnDom){
7362 var n = Roo.DomQuery.selectNode(selector, this.dom);
7363 return returnDom ? n : Roo.get(n);
7367 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7368 * @param {String} selector The CSS selector
7369 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7370 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7372 down : function(selector, returnDom){
7373 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7374 return returnDom ? n : Roo.get(n);
7378 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7379 * @param {String} group The group the DD object is member of
7380 * @param {Object} config The DD config object
7381 * @param {Object} overrides An object containing methods to override/implement on the DD object
7382 * @return {Roo.dd.DD} The DD object
7384 initDD : function(group, config, overrides){
7385 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7386 return Roo.apply(dd, overrides);
7390 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7391 * @param {String} group The group the DDProxy object is member of
7392 * @param {Object} config The DDProxy config object
7393 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7394 * @return {Roo.dd.DDProxy} The DDProxy object
7396 initDDProxy : function(group, config, overrides){
7397 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7398 return Roo.apply(dd, overrides);
7402 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7403 * @param {String} group The group the DDTarget object is member of
7404 * @param {Object} config The DDTarget config object
7405 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7406 * @return {Roo.dd.DDTarget} The DDTarget object
7408 initDDTarget : function(group, config, overrides){
7409 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7410 return Roo.apply(dd, overrides);
7414 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7415 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7416 * @param {Boolean} visible Whether the element is visible
7417 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7418 * @return {Roo.Element} this
7420 setVisible : function(visible, animate){
7422 if(this.visibilityMode == El.DISPLAY){
7423 this.setDisplayed(visible);
7426 this.dom.style.visibility = visible ? "visible" : "hidden";
7429 // closure for composites
7431 var visMode = this.visibilityMode;
7433 this.setOpacity(.01);
7434 this.setVisible(true);
7436 this.anim({opacity: { to: (visible?1:0) }},
7437 this.preanim(arguments, 1),
7438 null, .35, 'easeIn', function(){
7440 if(visMode == El.DISPLAY){
7441 dom.style.display = "none";
7443 dom.style.visibility = "hidden";
7445 Roo.get(dom).setOpacity(1);
7453 * Returns true if display is not "none"
7456 isDisplayed : function() {
7457 return this.getStyle("display") != "none";
7461 * Toggles the element's visibility or display, depending on visibility mode.
7462 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7463 * @return {Roo.Element} this
7465 toggle : function(animate){
7466 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7471 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7472 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7473 * @return {Roo.Element} this
7475 setDisplayed : function(value) {
7476 if(typeof value == "boolean"){
7477 value = value ? this.originalDisplay : "none";
7479 this.setStyle("display", value);
7484 * Tries to focus the element. Any exceptions are caught and ignored.
7485 * @return {Roo.Element} this
7487 focus : function() {
7495 * Tries to blur the element. Any exceptions are caught and ignored.
7496 * @return {Roo.Element} this
7506 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7507 * @param {String/Array} className The CSS class to add, or an array of classes
7508 * @return {Roo.Element} this
7510 addClass : function(className){
7511 if(className instanceof Array){
7512 for(var i = 0, len = className.length; i < len; i++) {
7513 this.addClass(className[i]);
7516 if(className && !this.hasClass(className)){
7517 this.dom.className = this.dom.className + " " + className;
7524 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7525 * @param {String/Array} className The CSS class to add, or an array of classes
7526 * @return {Roo.Element} this
7528 radioClass : function(className){
7529 var siblings = this.dom.parentNode.childNodes;
7530 for(var i = 0; i < siblings.length; i++) {
7531 var s = siblings[i];
7532 if(s.nodeType == 1){
7533 Roo.get(s).removeClass(className);
7536 this.addClass(className);
7541 * Removes one or more CSS classes from the element.
7542 * @param {String/Array} className The CSS class to remove, or an array of classes
7543 * @return {Roo.Element} this
7545 removeClass : function(className){
7546 if(!className || !this.dom.className){
7549 if(className instanceof Array){
7550 for(var i = 0, len = className.length; i < len; i++) {
7551 this.removeClass(className[i]);
7554 if(this.hasClass(className)){
7555 var re = this.classReCache[className];
7557 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7558 this.classReCache[className] = re;
7560 this.dom.className =
7561 this.dom.className.replace(re, " ");
7571 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7572 * @param {String} className The CSS class to toggle
7573 * @return {Roo.Element} this
7575 toggleClass : function(className){
7576 if(this.hasClass(className)){
7577 this.removeClass(className);
7579 this.addClass(className);
7585 * Checks if the specified CSS class exists on this element's DOM node.
7586 * @param {String} className The CSS class to check for
7587 * @return {Boolean} True if the class exists, else false
7589 hasClass : function(className){
7590 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7594 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7595 * @param {String} oldClassName The CSS class to replace
7596 * @param {String} newClassName The replacement CSS class
7597 * @return {Roo.Element} this
7599 replaceClass : function(oldClassName, newClassName){
7600 this.removeClass(oldClassName);
7601 this.addClass(newClassName);
7606 * Returns an object with properties matching the styles requested.
7607 * For example, el.getStyles('color', 'font-size', 'width') might return
7608 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7609 * @param {String} style1 A style name
7610 * @param {String} style2 A style name
7611 * @param {String} etc.
7612 * @return {Object} The style object
7614 getStyles : function(){
7615 var a = arguments, len = a.length, r = {};
7616 for(var i = 0; i < len; i++){
7617 r[a[i]] = this.getStyle(a[i]);
7623 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7624 * @param {String} property The style property whose value is returned.
7625 * @return {String} The current value of the style property for this element.
7627 getStyle : function(){
7628 return view && view.getComputedStyle ?
7630 var el = this.dom, v, cs, camel;
7631 if(prop == 'float'){
7634 if(el.style && (v = el.style[prop])){
7637 if(cs = view.getComputedStyle(el, "")){
7638 if(!(camel = propCache[prop])){
7639 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7646 var el = this.dom, v, cs, camel;
7647 if(prop == 'opacity'){
7648 if(typeof el.style.filter == 'string'){
7649 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7651 var fv = parseFloat(m[1]);
7653 return fv ? fv / 100 : 0;
7658 }else if(prop == 'float'){
7659 prop = "styleFloat";
7661 if(!(camel = propCache[prop])){
7662 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7664 if(v = el.style[camel]){
7667 if(cs = el.currentStyle){
7675 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7676 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7677 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7678 * @return {Roo.Element} this
7680 setStyle : function(prop, value){
7681 if(typeof prop == "string"){
7683 if (prop == 'float') {
7684 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7689 if(!(camel = propCache[prop])){
7690 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7693 if(camel == 'opacity') {
7694 this.setOpacity(value);
7696 this.dom.style[camel] = value;
7699 for(var style in prop){
7700 if(typeof prop[style] != "function"){
7701 this.setStyle(style, prop[style]);
7709 * More flexible version of {@link #setStyle} for setting style properties.
7710 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7711 * a function which returns such a specification.
7712 * @return {Roo.Element} this
7714 applyStyles : function(style){
7715 Roo.DomHelper.applyStyles(this.dom, style);
7720 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7721 * @return {Number} The X position of the element
7724 return D.getX(this.dom);
7728 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7729 * @return {Number} The Y position of the element
7732 return D.getY(this.dom);
7736 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7737 * @return {Array} The XY position of the element
7740 return D.getXY(this.dom);
7744 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7745 * @param {Number} The X position of the element
7746 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setX : function(x, animate){
7751 D.setX(this.dom, x);
7753 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7759 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7760 * @param {Number} The Y position of the element
7761 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7762 * @return {Roo.Element} this
7764 setY : function(y, animate){
7766 D.setY(this.dom, y);
7768 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7774 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7775 * @param {String} left The left CSS property value
7776 * @return {Roo.Element} this
7778 setLeft : function(left){
7779 this.setStyle("left", this.addUnits(left));
7784 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7785 * @param {String} top The top CSS property value
7786 * @return {Roo.Element} this
7788 setTop : function(top){
7789 this.setStyle("top", this.addUnits(top));
7794 * Sets the element's CSS right style.
7795 * @param {String} right The right CSS property value
7796 * @return {Roo.Element} this
7798 setRight : function(right){
7799 this.setStyle("right", this.addUnits(right));
7804 * Sets the element's CSS bottom style.
7805 * @param {String} bottom The bottom CSS property value
7806 * @return {Roo.Element} this
7808 setBottom : function(bottom){
7809 this.setStyle("bottom", this.addUnits(bottom));
7814 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7815 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7816 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7817 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7818 * @return {Roo.Element} this
7820 setXY : function(pos, animate){
7822 D.setXY(this.dom, pos);
7824 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7830 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7831 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7832 * @param {Number} x X value for new position (coordinates are page-based)
7833 * @param {Number} y Y value for new position (coordinates are page-based)
7834 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7835 * @return {Roo.Element} this
7837 setLocation : function(x, y, animate){
7838 this.setXY([x, y], this.preanim(arguments, 2));
7843 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7844 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7845 * @param {Number} x X value for new position (coordinates are page-based)
7846 * @param {Number} y Y value for new position (coordinates are page-based)
7847 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7848 * @return {Roo.Element} this
7850 moveTo : function(x, y, animate){
7851 this.setXY([x, y], this.preanim(arguments, 2));
7856 * Returns the region of the given element.
7857 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7858 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7860 getRegion : function(){
7861 return D.getRegion(this.dom);
7865 * Returns the offset height of the element
7866 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7867 * @return {Number} The element's height
7869 getHeight : function(contentHeight){
7870 var h = this.dom.offsetHeight || 0;
7871 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7875 * Returns the offset width of the element
7876 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7877 * @return {Number} The element's width
7879 getWidth : function(contentWidth){
7880 var w = this.dom.offsetWidth || 0;
7881 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7885 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7886 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7887 * if a height has not been set using CSS.
7890 getComputedHeight : function(){
7891 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7893 h = parseInt(this.getStyle('height'), 10) || 0;
7894 if(!this.isBorderBox()){
7895 h += this.getFrameWidth('tb');
7902 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7903 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7904 * if a width has not been set using CSS.
7907 getComputedWidth : function(){
7908 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7910 w = parseInt(this.getStyle('width'), 10) || 0;
7911 if(!this.isBorderBox()){
7912 w += this.getFrameWidth('lr');
7919 * Returns the size of the element.
7920 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7921 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7923 getSize : function(contentSize){
7924 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7928 * Returns the width and height of the viewport.
7929 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7931 getViewSize : function(){
7932 var d = this.dom, doc = document, aw = 0, ah = 0;
7933 if(d == doc || d == doc.body){
7934 return {width : D.getViewWidth(), height: D.getViewHeight()};
7937 width : d.clientWidth,
7938 height: d.clientHeight
7944 * Returns the value of the "value" attribute
7945 * @param {Boolean} asNumber true to parse the value as a number
7946 * @return {String/Number}
7948 getValue : function(asNumber){
7949 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7953 adjustWidth : function(width){
7954 if(typeof width == "number"){
7955 if(this.autoBoxAdjust && !this.isBorderBox()){
7956 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7966 adjustHeight : function(height){
7967 if(typeof height == "number"){
7968 if(this.autoBoxAdjust && !this.isBorderBox()){
7969 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7979 * Set the width of the element
7980 * @param {Number} width The new width
7981 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7982 * @return {Roo.Element} this
7984 setWidth : function(width, animate){
7985 width = this.adjustWidth(width);
7987 this.dom.style.width = this.addUnits(width);
7989 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7995 * Set the height of the element
7996 * @param {Number} height The new height
7997 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7998 * @return {Roo.Element} this
8000 setHeight : function(height, animate){
8001 height = this.adjustHeight(height);
8003 this.dom.style.height = this.addUnits(height);
8005 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8011 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8012 * @param {Number} width The new width
8013 * @param {Number} height The new height
8014 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8015 * @return {Roo.Element} this
8017 setSize : function(width, height, animate){
8018 if(typeof width == "object"){ // in case of object from getSize()
8019 height = width.height; width = width.width;
8021 width = this.adjustWidth(width); height = this.adjustHeight(height);
8023 this.dom.style.width = this.addUnits(width);
8024 this.dom.style.height = this.addUnits(height);
8026 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8032 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8033 * @param {Number} x X value for new position (coordinates are page-based)
8034 * @param {Number} y Y value for new position (coordinates are page-based)
8035 * @param {Number} width The new width
8036 * @param {Number} height The new height
8037 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8038 * @return {Roo.Element} this
8040 setBounds : function(x, y, width, height, animate){
8042 this.setSize(width, height);
8043 this.setLocation(x, y);
8045 width = this.adjustWidth(width); height = this.adjustHeight(height);
8046 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8047 this.preanim(arguments, 4), 'motion');
8053 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8054 * @param {Roo.lib.Region} region The region to fill
8055 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8056 * @return {Roo.Element} this
8058 setRegion : function(region, animate){
8059 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8064 * Appends an event handler
8066 * @param {String} eventName The type of event to append
8067 * @param {Function} fn The method the event invokes
8068 * @param {Object} scope (optional) The scope (this object) of the fn
8069 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8071 addListener : function(eventName, fn, scope, options){
8073 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8078 * Removes an event handler from this element
8079 * @param {String} eventName the type of event to remove
8080 * @param {Function} fn the method the event invokes
8081 * @return {Roo.Element} this
8083 removeListener : function(eventName, fn){
8084 Roo.EventManager.removeListener(this.dom, eventName, fn);
8089 * Removes all previous added listeners from this element
8090 * @return {Roo.Element} this
8092 removeAllListeners : function(){
8093 E.purgeElement(this.dom);
8097 relayEvent : function(eventName, observable){
8098 this.on(eventName, function(e){
8099 observable.fireEvent(eventName, e);
8104 * Set the opacity of the element
8105 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8106 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8107 * @return {Roo.Element} this
8109 setOpacity : function(opacity, animate){
8111 var s = this.dom.style;
8114 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8115 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8117 s.opacity = opacity;
8120 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8126 * Gets the left X coordinate
8127 * @param {Boolean} local True to get the local css position instead of page coordinate
8130 getLeft : function(local){
8134 return parseInt(this.getStyle("left"), 10) || 0;
8139 * Gets the right X coordinate of the element (element X position + element width)
8140 * @param {Boolean} local True to get the local css position instead of page coordinate
8143 getRight : function(local){
8145 return this.getX() + this.getWidth();
8147 return (this.getLeft(true) + this.getWidth()) || 0;
8152 * Gets the top Y coordinate
8153 * @param {Boolean} local True to get the local css position instead of page coordinate
8156 getTop : function(local) {
8160 return parseInt(this.getStyle("top"), 10) || 0;
8165 * Gets the bottom Y coordinate of the element (element Y position + element height)
8166 * @param {Boolean} local True to get the local css position instead of page coordinate
8169 getBottom : function(local){
8171 return this.getY() + this.getHeight();
8173 return (this.getTop(true) + this.getHeight()) || 0;
8178 * Initializes positioning on this element. If a desired position is not passed, it will make the
8179 * the element positioned relative IF it is not already positioned.
8180 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8181 * @param {Number} zIndex (optional) The zIndex to apply
8182 * @param {Number} x (optional) Set the page X position
8183 * @param {Number} y (optional) Set the page Y position
8185 position : function(pos, zIndex, x, y){
8187 if(this.getStyle('position') == 'static'){
8188 this.setStyle('position', 'relative');
8191 this.setStyle("position", pos);
8194 this.setStyle("z-index", zIndex);
8196 if(x !== undefined && y !== undefined){
8198 }else if(x !== undefined){
8200 }else if(y !== undefined){
8206 * Clear positioning back to the default when the document was loaded
8207 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8208 * @return {Roo.Element} this
8210 clearPositioning : function(value){
8218 "position" : "static"
8224 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8225 * snapshot before performing an update and then restoring the element.
8228 getPositioning : function(){
8229 var l = this.getStyle("left");
8230 var t = this.getStyle("top");
8232 "position" : this.getStyle("position"),
8234 "right" : l ? "" : this.getStyle("right"),
8236 "bottom" : t ? "" : this.getStyle("bottom"),
8237 "z-index" : this.getStyle("z-index")
8242 * Gets the width of the border(s) for the specified side(s)
8243 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8244 * passing lr would get the border (l)eft width + the border (r)ight width.
8245 * @return {Number} The width of the sides passed added together
8247 getBorderWidth : function(side){
8248 return this.addStyles(side, El.borders);
8252 * Gets the width of the padding(s) for the specified side(s)
8253 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8254 * passing lr would get the padding (l)eft + the padding (r)ight.
8255 * @return {Number} The padding of the sides passed added together
8257 getPadding : function(side){
8258 return this.addStyles(side, El.paddings);
8262 * Set positioning with an object returned by getPositioning().
8263 * @param {Object} posCfg
8264 * @return {Roo.Element} this
8266 setPositioning : function(pc){
8267 this.applyStyles(pc);
8268 if(pc.right == "auto"){
8269 this.dom.style.right = "";
8271 if(pc.bottom == "auto"){
8272 this.dom.style.bottom = "";
8278 fixDisplay : function(){
8279 if(this.getStyle("display") == "none"){
8280 this.setStyle("visibility", "hidden");
8281 this.setStyle("display", this.originalDisplay); // first try reverting to default
8282 if(this.getStyle("display") == "none"){ // if that fails, default to block
8283 this.setStyle("display", "block");
8289 * Quick set left and top adding default units
8290 * @param {String} left The left CSS property value
8291 * @param {String} top The top CSS property value
8292 * @return {Roo.Element} this
8294 setLeftTop : function(left, top){
8295 this.dom.style.left = this.addUnits(left);
8296 this.dom.style.top = this.addUnits(top);
8301 * Move this element relative to its current position.
8302 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8303 * @param {Number} distance How far to move the element in pixels
8304 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8305 * @return {Roo.Element} this
8307 move : function(direction, distance, animate){
8308 var xy = this.getXY();
8309 direction = direction.toLowerCase();
8313 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8317 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8322 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8327 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8334 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8335 * @return {Roo.Element} this
8338 if(!this.isClipped){
8339 this.isClipped = true;
8340 this.originalClip = {
8341 "o": this.getStyle("overflow"),
8342 "x": this.getStyle("overflow-x"),
8343 "y": this.getStyle("overflow-y")
8345 this.setStyle("overflow", "hidden");
8346 this.setStyle("overflow-x", "hidden");
8347 this.setStyle("overflow-y", "hidden");
8353 * Return clipping (overflow) to original clipping before clip() was called
8354 * @return {Roo.Element} this
8356 unclip : function(){
8358 this.isClipped = false;
8359 var o = this.originalClip;
8360 if(o.o){this.setStyle("overflow", o.o);}
8361 if(o.x){this.setStyle("overflow-x", o.x);}
8362 if(o.y){this.setStyle("overflow-y", o.y);}
8369 * Gets the x,y coordinates specified by the anchor position on the element.
8370 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8371 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8372 * {width: (target width), height: (target height)} (defaults to the element's current size)
8373 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8374 * @return {Array} [x, y] An array containing the element's x and y coordinates
8376 getAnchorXY : function(anchor, local, s){
8377 //Passing a different size is useful for pre-calculating anchors,
8378 //especially for anchored animations that change the el size.
8380 var w, h, vp = false;
8383 if(d == document.body || d == document){
8385 w = D.getViewWidth(); h = D.getViewHeight();
8387 w = this.getWidth(); h = this.getHeight();
8390 w = s.width; h = s.height;
8392 var x = 0, y = 0, r = Math.round;
8393 switch((anchor || "tl").toLowerCase()){
8435 var sc = this.getScroll();
8436 return [x + sc.left, y + sc.top];
8438 //Add the element's offset xy
8439 var o = this.getXY();
8440 return [x+o[0], y+o[1]];
8444 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8445 * supported position values.
8446 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8447 * @param {String} position The position to align to.
8448 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8449 * @return {Array} [x, y]
8451 getAlignToXY : function(el, p, o){
8455 throw "Element.alignTo with an element that doesn't exist";
8457 var c = false; //constrain to viewport
8458 var p1 = "", p2 = "";
8465 }else if(p.indexOf("-") == -1){
8468 p = p.toLowerCase();
8469 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8471 throw "Element.alignTo with an invalid alignment " + p;
8473 p1 = m[1]; p2 = m[2]; c = !!m[3];
8475 //Subtract the aligned el's internal xy from the target's offset xy
8476 //plus custom offset to get the aligned el's new offset xy
8477 var a1 = this.getAnchorXY(p1, true);
8478 var a2 = el.getAnchorXY(p2, false);
8479 var x = a2[0] - a1[0] + o[0];
8480 var y = a2[1] - a1[1] + o[1];
8482 //constrain the aligned el to viewport if necessary
8483 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8484 // 5px of margin for ie
8485 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8487 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8488 //perpendicular to the vp border, allow the aligned el to slide on that border,
8489 //otherwise swap the aligned el to the opposite border of the target.
8490 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8491 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8492 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8493 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8496 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8497 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8499 if((x+w) > dw + scrollX){
8500 x = swapX ? r.left-w : dw+scrollX-w;
8503 x = swapX ? r.right : scrollX;
8505 if((y+h) > dh + scrollY){
8506 y = swapY ? r.top-h : dh+scrollY-h;
8509 y = swapY ? r.bottom : scrollY;
8516 getConstrainToXY : function(){
8517 var os = {top:0, left:0, bottom:0, right: 0};
8519 return function(el, local, offsets, proposedXY){
8521 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8523 var vw, vh, vx = 0, vy = 0;
8524 if(el.dom == document.body || el.dom == document){
8525 vw = Roo.lib.Dom.getViewWidth();
8526 vh = Roo.lib.Dom.getViewHeight();
8528 vw = el.dom.clientWidth;
8529 vh = el.dom.clientHeight;
8531 var vxy = el.getXY();
8537 var s = el.getScroll();
8539 vx += offsets.left + s.left;
8540 vy += offsets.top + s.top;
8542 vw -= offsets.right;
8543 vh -= offsets.bottom;
8548 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8549 var x = xy[0], y = xy[1];
8550 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8552 // only move it if it needs it
8555 // first validate right/bottom
8564 // then make sure top/left isn't negative
8573 return moved ? [x, y] : false;
8578 adjustForConstraints : function(xy, parent, offsets){
8579 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8583 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8584 * document it aligns it to the viewport.
8585 * The position parameter is optional, and can be specified in any one of the following formats:
8587 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8588 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8589 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8590 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8591 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8592 * element's anchor point, and the second value is used as the target's anchor point.</li>
8594 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8595 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8596 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8597 * that specified in order to enforce the viewport constraints.
8598 * Following are all of the supported anchor positions:
8601 ----- -----------------------------
8602 tl The top left corner (default)
8603 t The center of the top edge
8604 tr The top right corner
8605 l The center of the left edge
8606 c In the center of the element
8607 r The center of the right edge
8608 bl The bottom left corner
8609 b The center of the bottom edge
8610 br The bottom right corner
8614 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8615 el.alignTo("other-el");
8617 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8618 el.alignTo("other-el", "tr?");
8620 // align the bottom right corner of el with the center left edge of other-el
8621 el.alignTo("other-el", "br-l?");
8623 // align the center of el with the bottom left corner of other-el and
8624 // adjust the x position by -6 pixels (and the y position by 0)
8625 el.alignTo("other-el", "c-bl", [-6, 0]);
8627 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8628 * @param {String} position The position to align to.
8629 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8630 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8631 * @return {Roo.Element} this
8633 alignTo : function(element, position, offsets, animate){
8634 var xy = this.getAlignToXY(element, position, offsets);
8635 this.setXY(xy, this.preanim(arguments, 3));
8640 * Anchors an element to another element and realigns it when the window is resized.
8641 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8642 * @param {String} position The position to align to.
8643 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8644 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8645 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8646 * is a number, it is used as the buffer delay (defaults to 50ms).
8647 * @param {Function} callback The function to call after the animation finishes
8648 * @return {Roo.Element} this
8650 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8651 var action = function(){
8652 this.alignTo(el, alignment, offsets, animate);
8653 Roo.callback(callback, this);
8655 Roo.EventManager.onWindowResize(action, this);
8656 var tm = typeof monitorScroll;
8657 if(tm != 'undefined'){
8658 Roo.EventManager.on(window, 'scroll', action, this,
8659 {buffer: tm == 'number' ? monitorScroll : 50});
8661 action.call(this); // align immediately
8665 * Clears any opacity settings from this element. Required in some cases for IE.
8666 * @return {Roo.Element} this
8668 clearOpacity : function(){
8669 if (window.ActiveXObject) {
8670 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8671 this.dom.style.filter = "";
8674 this.dom.style.opacity = "";
8675 this.dom.style["-moz-opacity"] = "";
8676 this.dom.style["-khtml-opacity"] = "";
8682 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8683 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8684 * @return {Roo.Element} this
8686 hide : function(animate){
8687 this.setVisible(false, this.preanim(arguments, 0));
8692 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8693 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694 * @return {Roo.Element} this
8696 show : function(animate){
8697 this.setVisible(true, this.preanim(arguments, 0));
8702 * @private Test if size has a unit, otherwise appends the default
8704 addUnits : function(size){
8705 return Roo.Element.addUnits(size, this.defaultUnit);
8709 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8710 * @return {Roo.Element} this
8712 beginMeasure : function(){
8714 if(el.offsetWidth || el.offsetHeight){
8715 return this; // offsets work already
8718 var p = this.dom, b = document.body; // start with this element
8719 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8720 var pe = Roo.get(p);
8721 if(pe.getStyle('display') == 'none'){
8722 changed.push({el: p, visibility: pe.getStyle("visibility")});
8723 p.style.visibility = "hidden";
8724 p.style.display = "block";
8728 this._measureChanged = changed;
8734 * Restores displays to before beginMeasure was called
8735 * @return {Roo.Element} this
8737 endMeasure : function(){
8738 var changed = this._measureChanged;
8740 for(var i = 0, len = changed.length; i < len; i++) {
8742 r.el.style.visibility = r.visibility;
8743 r.el.style.display = "none";
8745 this._measureChanged = null;
8751 * Update the innerHTML of this element, optionally searching for and processing scripts
8752 * @param {String} html The new HTML
8753 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8754 * @param {Function} callback For async script loading you can be noticed when the update completes
8755 * @return {Roo.Element} this
8757 update : function(html, loadScripts, callback){
8758 if(typeof html == "undefined"){
8761 if(loadScripts !== true){
8762 this.dom.innerHTML = html;
8763 if(typeof callback == "function"){
8771 html += '<span id="' + id + '"></span>';
8773 E.onAvailable(id, function(){
8774 var hd = document.getElementsByTagName("head")[0];
8775 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8776 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8777 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8780 while(match = re.exec(html)){
8781 var attrs = match[1];
8782 var srcMatch = attrs ? attrs.match(srcRe) : false;
8783 if(srcMatch && srcMatch[2]){
8784 var s = document.createElement("script");
8785 s.src = srcMatch[2];
8786 var typeMatch = attrs.match(typeRe);
8787 if(typeMatch && typeMatch[2]){
8788 s.type = typeMatch[2];
8791 }else if(match[2] && match[2].length > 0){
8792 if(window.execScript) {
8793 window.execScript(match[2]);
8801 window.eval(match[2]);
8805 var el = document.getElementById(id);
8806 if(el){el.parentNode.removeChild(el);}
8807 if(typeof callback == "function"){
8811 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8816 * Direct access to the UpdateManager update() method (takes the same parameters).
8817 * @param {String/Function} url The url for this request or a function to call to get the url
8818 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8819 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8820 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8821 * @return {Roo.Element} this
8824 var um = this.getUpdateManager();
8825 um.update.apply(um, arguments);
8830 * Gets this element's UpdateManager
8831 * @return {Roo.UpdateManager} The UpdateManager
8833 getUpdateManager : function(){
8834 if(!this.updateManager){
8835 this.updateManager = new Roo.UpdateManager(this);
8837 return this.updateManager;
8841 * Disables text selection for this element (normalized across browsers)
8842 * @return {Roo.Element} this
8844 unselectable : function(){
8845 this.dom.unselectable = "on";
8846 this.swallowEvent("selectstart", true);
8847 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8848 this.addClass("x-unselectable");
8853 * Calculates the x, y to center this element on the screen
8854 * @return {Array} The x, y values [x, y]
8856 getCenterXY : function(){
8857 return this.getAlignToXY(document, 'c-c');
8861 * Centers the Element in either the viewport, or another Element.
8862 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8864 center : function(centerIn){
8865 this.alignTo(centerIn || document, 'c-c');
8870 * Tests various css rules/browsers to determine if this element uses a border box
8873 isBorderBox : function(){
8874 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8878 * Return a box {x, y, width, height} that can be used to set another elements
8879 * size/location to match this element.
8880 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8881 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8882 * @return {Object} box An object in the format {x, y, width, height}
8884 getBox : function(contentBox, local){
8889 var left = parseInt(this.getStyle("left"), 10) || 0;
8890 var top = parseInt(this.getStyle("top"), 10) || 0;
8893 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8895 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8897 var l = this.getBorderWidth("l")+this.getPadding("l");
8898 var r = this.getBorderWidth("r")+this.getPadding("r");
8899 var t = this.getBorderWidth("t")+this.getPadding("t");
8900 var b = this.getBorderWidth("b")+this.getPadding("b");
8901 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8903 bx.right = bx.x + bx.width;
8904 bx.bottom = bx.y + bx.height;
8909 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8910 for more information about the sides.
8911 * @param {String} sides
8914 getFrameWidth : function(sides, onlyContentBox){
8915 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8919 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8920 * @param {Object} box The box to fill {x, y, width, height}
8921 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8922 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8923 * @return {Roo.Element} this
8925 setBox : function(box, adjust, animate){
8926 var w = box.width, h = box.height;
8927 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8928 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8929 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8931 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8936 * Forces the browser to repaint this element
8937 * @return {Roo.Element} this
8939 repaint : function(){
8941 this.addClass("x-repaint");
8942 setTimeout(function(){
8943 Roo.get(dom).removeClass("x-repaint");
8949 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8950 * then it returns the calculated width of the sides (see getPadding)
8951 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8952 * @return {Object/Number}
8954 getMargins : function(side){
8957 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8958 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8959 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8960 right: parseInt(this.getStyle("margin-right"), 10) || 0
8963 return this.addStyles(side, El.margins);
8968 addStyles : function(sides, styles){
8970 for(var i = 0, len = sides.length; i < len; i++){
8971 v = this.getStyle(styles[sides.charAt(i)]);
8973 w = parseInt(v, 10);
8981 * Creates a proxy element of this element
8982 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8983 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8984 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8985 * @return {Roo.Element} The new proxy element
8987 createProxy : function(config, renderTo, matchBox){
8989 renderTo = Roo.getDom(renderTo);
8991 renderTo = document.body;
8993 config = typeof config == "object" ?
8994 config : {tag : "div", cls: config};
8995 var proxy = Roo.DomHelper.append(renderTo, config, true);
8997 proxy.setBox(this.getBox());
9003 * Puts a mask over this element to disable user interaction. Requires core.css.
9004 * This method can only be applied to elements which accept child nodes.
9005 * @param {String} msg (optional) A message to display in the mask
9006 * @param {String} msgCls (optional) A css class to apply to the msg element
9007 * @return {Element} The mask element
9009 mask : function(msg, msgCls)
9011 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9012 this.setStyle("position", "relative");
9015 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9017 this.addClass("x-masked");
9018 this._mask.setDisplayed(true);
9023 while (dom && dom.style) {
9024 if (!isNaN(parseInt(dom.style.zIndex))) {
9025 z = Math.max(z, parseInt(dom.style.zIndex));
9027 dom = dom.parentNode;
9029 // if we are masking the body - then it hides everything..
9030 if (this.dom == document.body) {
9032 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9033 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9036 if(typeof msg == 'string'){
9038 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9040 var mm = this._maskMsg;
9041 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9042 if (mm.dom.firstChild) { // weird IE issue?
9043 mm.dom.firstChild.innerHTML = msg;
9045 mm.setDisplayed(true);
9047 mm.setStyle('z-index', z + 102);
9049 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9050 this._mask.setHeight(this.getHeight());
9052 this._mask.setStyle('z-index', z + 100);
9058 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9059 * it is cached for reuse.
9061 unmask : function(removeEl){
9063 if(removeEl === true){
9064 this._mask.remove();
9067 this._maskMsg.remove();
9068 delete this._maskMsg;
9071 this._mask.setDisplayed(false);
9073 this._maskMsg.setDisplayed(false);
9077 this.removeClass("x-masked");
9081 * Returns true if this element is masked
9084 isMasked : function(){
9085 return this._mask && this._mask.isVisible();
9089 * Creates an iframe shim for this element to keep selects and other windowed objects from
9091 * @return {Roo.Element} The new shim element
9093 createShim : function(){
9094 var el = document.createElement('iframe');
9095 el.frameBorder = 'no';
9096 el.className = 'roo-shim';
9097 if(Roo.isIE && Roo.isSecure){
9098 el.src = Roo.SSL_SECURE_URL;
9100 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9101 shim.autoBoxAdjust = false;
9106 * Removes this element from the DOM and deletes it from the cache
9108 remove : function(){
9109 if(this.dom.parentNode){
9110 this.dom.parentNode.removeChild(this.dom);
9112 delete El.cache[this.dom.id];
9116 * Sets up event handlers to add and remove a css class when the mouse is over this element
9117 * @param {String} className
9118 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9119 * mouseout events for children elements
9120 * @return {Roo.Element} this
9122 addClassOnOver : function(className, preventFlicker){
9123 this.on("mouseover", function(){
9124 Roo.fly(this, '_internal').addClass(className);
9126 var removeFn = function(e){
9127 if(preventFlicker !== true || !e.within(this, true)){
9128 Roo.fly(this, '_internal').removeClass(className);
9131 this.on("mouseout", removeFn, this.dom);
9136 * Sets up event handlers to add and remove a css class when this element has the focus
9137 * @param {String} className
9138 * @return {Roo.Element} this
9140 addClassOnFocus : function(className){
9141 this.on("focus", function(){
9142 Roo.fly(this, '_internal').addClass(className);
9144 this.on("blur", function(){
9145 Roo.fly(this, '_internal').removeClass(className);
9150 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9151 * @param {String} className
9152 * @return {Roo.Element} this
9154 addClassOnClick : function(className){
9156 this.on("mousedown", function(){
9157 Roo.fly(dom, '_internal').addClass(className);
9158 var d = Roo.get(document);
9159 var fn = function(){
9160 Roo.fly(dom, '_internal').removeClass(className);
9161 d.removeListener("mouseup", fn);
9163 d.on("mouseup", fn);
9169 * Stops the specified event from bubbling and optionally prevents the default action
9170 * @param {String} eventName
9171 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9172 * @return {Roo.Element} this
9174 swallowEvent : function(eventName, preventDefault){
9175 var fn = function(e){
9176 e.stopPropagation();
9181 if(eventName instanceof Array){
9182 for(var i = 0, len = eventName.length; i < len; i++){
9183 this.on(eventName[i], fn);
9187 this.on(eventName, fn);
9194 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9197 * Sizes this element to its parent element's dimensions performing
9198 * neccessary box adjustments.
9199 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9200 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9201 * @return {Roo.Element} this
9203 fitToParent : function(monitorResize, targetParent) {
9204 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9205 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9206 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9209 var p = Roo.get(targetParent || this.dom.parentNode);
9210 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9211 if (monitorResize === true) {
9212 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9213 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9219 * Gets the next sibling, skipping text nodes
9220 * @return {HTMLElement} The next sibling or null
9222 getNextSibling : function(){
9223 var n = this.dom.nextSibling;
9224 while(n && n.nodeType != 1){
9231 * Gets the previous sibling, skipping text nodes
9232 * @return {HTMLElement} The previous sibling or null
9234 getPrevSibling : function(){
9235 var n = this.dom.previousSibling;
9236 while(n && n.nodeType != 1){
9237 n = n.previousSibling;
9244 * Appends the passed element(s) to this element
9245 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9246 * @return {Roo.Element} this
9248 appendChild: function(el){
9255 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9256 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9257 * automatically generated with the specified attributes.
9258 * @param {HTMLElement} insertBefore (optional) a child element of this element
9259 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9260 * @return {Roo.Element} The new child element
9262 createChild: function(config, insertBefore, returnDom){
9263 config = config || {tag:'div'};
9265 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9267 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9271 * Appends this element to the passed element
9272 * @param {String/HTMLElement/Element} el The new parent element
9273 * @return {Roo.Element} this
9275 appendTo: function(el){
9276 el = Roo.getDom(el);
9277 el.appendChild(this.dom);
9282 * Inserts this element before the passed element in the DOM
9283 * @param {String/HTMLElement/Element} el The element to insert before
9284 * @return {Roo.Element} this
9286 insertBefore: function(el){
9287 el = Roo.getDom(el);
9288 el.parentNode.insertBefore(this.dom, el);
9293 * Inserts this element after the passed element in the DOM
9294 * @param {String/HTMLElement/Element} el The element to insert after
9295 * @return {Roo.Element} this
9297 insertAfter: function(el){
9298 el = Roo.getDom(el);
9299 el.parentNode.insertBefore(this.dom, el.nextSibling);
9304 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9305 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9306 * @return {Roo.Element} The new child
9308 insertFirst: function(el, returnDom){
9310 if(typeof el == 'object' && !el.nodeType){ // dh config
9311 return this.createChild(el, this.dom.firstChild, returnDom);
9313 el = Roo.getDom(el);
9314 this.dom.insertBefore(el, this.dom.firstChild);
9315 return !returnDom ? Roo.get(el) : el;
9320 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9321 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9322 * @param {String} where (optional) 'before' or 'after' defaults to before
9323 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9324 * @return {Roo.Element} the inserted Element
9326 insertSibling: function(el, where, returnDom){
9327 where = where ? where.toLowerCase() : 'before';
9329 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9331 if(typeof el == 'object' && !el.nodeType){ // dh config
9332 if(where == 'after' && !this.dom.nextSibling){
9333 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9335 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9339 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9340 where == 'before' ? this.dom : this.dom.nextSibling);
9349 * Creates and wraps this element with another element
9350 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9351 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9352 * @return {HTMLElement/Element} The newly created wrapper element
9354 wrap: function(config, returnDom){
9356 config = {tag: "div"};
9358 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9359 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9364 * Replaces the passed element with this element
9365 * @param {String/HTMLElement/Element} el The element to replace
9366 * @return {Roo.Element} this
9368 replace: function(el){
9370 this.insertBefore(el);
9376 * Inserts an html fragment into this element
9377 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9378 * @param {String} html The HTML fragment
9379 * @param {Boolean} returnEl True to return an Roo.Element
9380 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9382 insertHtml : function(where, html, returnEl){
9383 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9384 return returnEl ? Roo.get(el) : el;
9388 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9389 * @param {Object} o The object with the attributes
9390 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9391 * @return {Roo.Element} this
9393 set : function(o, useSet){
9395 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9397 if(attr == "style" || typeof o[attr] == "function") { continue; }
9399 el.className = o["cls"];
9402 el.setAttribute(attr, o[attr]);
9409 Roo.DomHelper.applyStyles(el, o.style);
9415 * Convenience method for constructing a KeyMap
9416 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9417 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9418 * @param {Function} fn The function to call
9419 * @param {Object} scope (optional) The scope of the function
9420 * @return {Roo.KeyMap} The KeyMap created
9422 addKeyListener : function(key, fn, scope){
9424 if(typeof key != "object" || key instanceof Array){
9440 return new Roo.KeyMap(this, config);
9444 * Creates a KeyMap for this element
9445 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9446 * @return {Roo.KeyMap} The KeyMap created
9448 addKeyMap : function(config){
9449 return new Roo.KeyMap(this, config);
9453 * Returns true if this element is scrollable.
9456 isScrollable : function(){
9458 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9462 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9463 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9464 * @param {Number} value The new scroll value
9465 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9466 * @return {Element} this
9469 scrollTo : function(side, value, animate){
9470 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9472 this.dom[prop] = value;
9474 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9475 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9481 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9482 * within this element's scrollable range.
9483 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9484 * @param {Number} distance How far to scroll the element in pixels
9485 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9486 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9487 * was scrolled as far as it could go.
9489 scroll : function(direction, distance, animate){
9490 if(!this.isScrollable()){
9494 var l = el.scrollLeft, t = el.scrollTop;
9495 var w = el.scrollWidth, h = el.scrollHeight;
9496 var cw = el.clientWidth, ch = el.clientHeight;
9497 direction = direction.toLowerCase();
9498 var scrolled = false;
9499 var a = this.preanim(arguments, 2);
9504 var v = Math.min(l + distance, w-cw);
9505 this.scrollTo("left", v, a);
9512 var v = Math.max(l - distance, 0);
9513 this.scrollTo("left", v, a);
9521 var v = Math.max(t - distance, 0);
9522 this.scrollTo("top", v, a);
9530 var v = Math.min(t + distance, h-ch);
9531 this.scrollTo("top", v, a);
9540 * Translates the passed page coordinates into left/top css values for this element
9541 * @param {Number/Array} x The page x or an array containing [x, y]
9542 * @param {Number} y The page y
9543 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9545 translatePoints : function(x, y){
9546 if(typeof x == 'object' || x instanceof Array){
9549 var p = this.getStyle('position');
9550 var o = this.getXY();
9552 var l = parseInt(this.getStyle('left'), 10);
9553 var t = parseInt(this.getStyle('top'), 10);
9556 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9559 t = (p == "relative") ? 0 : this.dom.offsetTop;
9562 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9566 * Returns the current scroll position of the element.
9567 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9569 getScroll : function(){
9570 var d = this.dom, doc = document;
9571 if(d == doc || d == doc.body){
9572 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9573 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9574 return {left: l, top: t};
9576 return {left: d.scrollLeft, top: d.scrollTop};
9581 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9582 * are convert to standard 6 digit hex color.
9583 * @param {String} attr The css attribute
9584 * @param {String} defaultValue The default value to use when a valid color isn't found
9585 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9588 getColor : function(attr, defaultValue, prefix){
9589 var v = this.getStyle(attr);
9590 if(!v || v == "transparent" || v == "inherit") {
9591 return defaultValue;
9593 var color = typeof prefix == "undefined" ? "#" : prefix;
9594 if(v.substr(0, 4) == "rgb("){
9595 var rvs = v.slice(4, v.length -1).split(",");
9596 for(var i = 0; i < 3; i++){
9597 var h = parseInt(rvs[i]).toString(16);
9604 if(v.substr(0, 1) == "#"){
9606 for(var i = 1; i < 4; i++){
9607 var c = v.charAt(i);
9610 }else if(v.length == 7){
9611 color += v.substr(1);
9615 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9619 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9620 * gradient background, rounded corners and a 4-way shadow.
9621 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9622 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9623 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9624 * @return {Roo.Element} this
9626 boxWrap : function(cls){
9627 cls = cls || 'x-box';
9628 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9629 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9634 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9635 * @param {String} namespace The namespace in which to look for the attribute
9636 * @param {String} name The attribute name
9637 * @return {String} The attribute value
9639 getAttributeNS : Roo.isIE ? function(ns, name){
9641 var type = typeof d[ns+":"+name];
9642 if(type != 'undefined' && type != 'unknown'){
9643 return d[ns+":"+name];
9646 } : function(ns, name){
9648 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9653 * Sets or Returns the value the dom attribute value
9654 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9655 * @param {String} value (optional) The value to set the attribute to
9656 * @return {String} The attribute value
9658 attr : function(name){
9659 if (arguments.length > 1) {
9660 this.dom.setAttribute(name, arguments[1]);
9661 return arguments[1];
9663 if (typeof(name) == 'object') {
9664 for(var i in name) {
9665 this.attr(i, name[i]);
9671 if (!this.dom.hasAttribute(name)) {
9674 return this.dom.getAttribute(name);
9681 var ep = El.prototype;
9684 * Appends an event handler (Shorthand for addListener)
9685 * @param {String} eventName The type of event to append
9686 * @param {Function} fn The method the event invokes
9687 * @param {Object} scope (optional) The scope (this object) of the fn
9688 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9691 ep.on = ep.addListener;
9693 ep.mon = ep.addListener;
9696 * Removes an event handler from this element (shorthand for removeListener)
9697 * @param {String} eventName the type of event to remove
9698 * @param {Function} fn the method the event invokes
9699 * @return {Roo.Element} this
9702 ep.un = ep.removeListener;
9705 * true to automatically adjust width and height settings for box-model issues (default to true)
9707 ep.autoBoxAdjust = true;
9710 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9713 El.addUnits = function(v, defaultUnit){
9714 if(v === "" || v == "auto"){
9717 if(v === undefined){
9720 if(typeof v == "number" || !El.unitPattern.test(v)){
9721 return v + (defaultUnit || 'px');
9726 // special markup used throughout Roo when box wrapping elements
9727 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9729 * Visibility mode constant - Use visibility to hide element
9735 * Visibility mode constant - Use display to hide element
9741 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9742 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9743 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9755 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9756 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9757 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9758 * @return {Element} The Element object
9761 El.get = function(el){
9763 if(!el){ return null; }
9764 if(typeof el == "string"){ // element id
9765 if(!(elm = document.getElementById(el))){
9768 if(ex = El.cache[el]){
9771 ex = El.cache[el] = new El(elm);
9774 }else if(el.tagName){ // dom element
9778 if(ex = El.cache[id]){
9781 ex = El.cache[id] = new El(el);
9784 }else if(el instanceof El){
9786 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9787 // catch case where it hasn't been appended
9788 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9791 }else if(el.isComposite){
9793 }else if(el instanceof Array){
9794 return El.select(el);
9795 }else if(el == document){
9796 // create a bogus element object representing the document object
9798 var f = function(){};
9799 f.prototype = El.prototype;
9801 docEl.dom = document;
9809 El.uncache = function(el){
9810 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9812 delete El.cache[a[i].id || a[i]];
9818 // Garbage collection - uncache elements/purge listeners on orphaned elements
9819 // so we don't hold a reference and cause the browser to retain them
9820 El.garbageCollect = function(){
9821 if(!Roo.enableGarbageCollector){
9822 clearInterval(El.collectorThread);
9825 for(var eid in El.cache){
9826 var el = El.cache[eid], d = el.dom;
9827 // -------------------------------------------------------
9828 // Determining what is garbage:
9829 // -------------------------------------------------------
9831 // dom node is null, definitely garbage
9832 // -------------------------------------------------------
9834 // no parentNode == direct orphan, definitely garbage
9835 // -------------------------------------------------------
9836 // !d.offsetParent && !document.getElementById(eid)
9837 // display none elements have no offsetParent so we will
9838 // also try to look it up by it's id. However, check
9839 // offsetParent first so we don't do unneeded lookups.
9840 // This enables collection of elements that are not orphans
9841 // directly, but somewhere up the line they have an orphan
9843 // -------------------------------------------------------
9844 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9845 delete El.cache[eid];
9846 if(d && Roo.enableListenerCollection){
9852 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9856 El.Flyweight = function(dom){
9859 El.Flyweight.prototype = El.prototype;
9861 El._flyweights = {};
9863 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9864 * the dom node can be overwritten by other code.
9865 * @param {String/HTMLElement} el The dom node or id
9866 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9867 * prevent conflicts (e.g. internally Roo uses "_internal")
9869 * @return {Element} The shared Element object
9871 El.fly = function(el, named){
9872 named = named || '_global';
9873 el = Roo.getDom(el);
9877 if(!El._flyweights[named]){
9878 El._flyweights[named] = new El.Flyweight();
9880 El._flyweights[named].dom = el;
9881 return El._flyweights[named];
9885 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9886 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9887 * Shorthand of {@link Roo.Element#get}
9888 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9889 * @return {Element} The Element object
9895 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9896 * the dom node can be overwritten by other code.
9897 * Shorthand of {@link Roo.Element#fly}
9898 * @param {String/HTMLElement} el The dom node or id
9899 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9900 * prevent conflicts (e.g. internally Roo uses "_internal")
9902 * @return {Element} The shared Element object
9908 // speedy lookup for elements never to box adjust
9909 var noBoxAdjust = Roo.isStrict ? {
9912 input:1, select:1, textarea:1
9914 if(Roo.isIE || Roo.isGecko){
9915 noBoxAdjust['button'] = 1;
9919 Roo.EventManager.on(window, 'unload', function(){
9921 delete El._flyweights;
9929 Roo.Element.selectorFunction = Roo.DomQuery.select;
9932 Roo.Element.select = function(selector, unique, root){
9934 if(typeof selector == "string"){
9935 els = Roo.Element.selectorFunction(selector, root);
9936 }else if(selector.length !== undefined){
9939 throw "Invalid selector";
9941 if(unique === true){
9942 return new Roo.CompositeElement(els);
9944 return new Roo.CompositeElementLite(els);
9948 * Selects elements based on the passed CSS selector to enable working on them as 1.
9949 * @param {String/Array} selector The CSS selector or an array of elements
9950 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9951 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9952 * @return {CompositeElementLite/CompositeElement}
9956 Roo.select = Roo.Element.select;
9973 * Ext JS Library 1.1.1
9974 * Copyright(c) 2006-2007, Ext JS, LLC.
9976 * Originally Released Under LGPL - original licence link has changed is not relivant.
9979 * <script type="text/javascript">
9984 //Notifies Element that fx methods are available
9985 Roo.enableFx = true;
9989 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9990 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9991 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9992 * Element effects to work.</p><br/>
9994 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9995 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9996 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9997 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9998 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9999 * expected results and should be done with care.</p><br/>
10001 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10002 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10005 ----- -----------------------------
10006 tl The top left corner
10007 t The center of the top edge
10008 tr The top right corner
10009 l The center of the left edge
10010 r The center of the right edge
10011 bl The bottom left corner
10012 b The center of the bottom edge
10013 br The bottom right corner
10015 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10016 * below are common options that can be passed to any Fx method.</b>
10017 * @cfg {Function} callback A function called when the effect is finished
10018 * @cfg {Object} scope The scope of the effect function
10019 * @cfg {String} easing A valid Easing value for the effect
10020 * @cfg {String} afterCls A css class to apply after the effect
10021 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10022 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10023 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10024 * effects that end with the element being visually hidden, ignored otherwise)
10025 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10026 * a function which returns such a specification that will be applied to the Element after the effect finishes
10027 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10028 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10029 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10033 * Slides the element into view. An anchor point can be optionally passed to set the point of
10034 * origin for the slide effect. This function automatically handles wrapping the element with
10035 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10038 // default: slide the element in from the top
10041 // custom: slide the element in from the right with a 2-second duration
10042 el.slideIn('r', { duration: 2 });
10044 // common config options shown with default values
10050 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10051 * @param {Object} options (optional) Object literal with any of the Fx config options
10052 * @return {Roo.Element} The Element
10054 slideIn : function(anchor, o){
10055 var el = this.getFxEl();
10058 el.queueFx(o, function(){
10060 anchor = anchor || "t";
10062 // fix display to visibility
10065 // restore values after effect
10066 var r = this.getFxRestore();
10067 var b = this.getBox();
10068 // fixed size for slide
10072 var wrap = this.fxWrap(r.pos, o, "hidden");
10074 var st = this.dom.style;
10075 st.visibility = "visible";
10076 st.position = "absolute";
10078 // clear out temp styles after slide and unwrap
10079 var after = function(){
10080 el.fxUnwrap(wrap, r.pos, o);
10081 st.width = r.width;
10082 st.height = r.height;
10085 // time to calc the positions
10086 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10088 switch(anchor.toLowerCase()){
10090 wrap.setSize(b.width, 0);
10091 st.left = st.bottom = "0";
10095 wrap.setSize(0, b.height);
10096 st.right = st.top = "0";
10100 wrap.setSize(0, b.height);
10101 wrap.setX(b.right);
10102 st.left = st.top = "0";
10103 a = {width: bw, points: pt};
10106 wrap.setSize(b.width, 0);
10107 wrap.setY(b.bottom);
10108 st.left = st.top = "0";
10109 a = {height: bh, points: pt};
10112 wrap.setSize(0, 0);
10113 st.right = st.bottom = "0";
10114 a = {width: bw, height: bh};
10117 wrap.setSize(0, 0);
10118 wrap.setY(b.y+b.height);
10119 st.right = st.top = "0";
10120 a = {width: bw, height: bh, points: pt};
10123 wrap.setSize(0, 0);
10124 wrap.setXY([b.right, b.bottom]);
10125 st.left = st.top = "0";
10126 a = {width: bw, height: bh, points: pt};
10129 wrap.setSize(0, 0);
10130 wrap.setX(b.x+b.width);
10131 st.left = st.bottom = "0";
10132 a = {width: bw, height: bh, points: pt};
10135 this.dom.style.visibility = "visible";
10138 arguments.callee.anim = wrap.fxanim(a,
10148 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10149 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10150 * 'hidden') but block elements will still take up space in the document. The element must be removed
10151 * from the DOM using the 'remove' config option if desired. This function automatically handles
10152 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10155 // default: slide the element out to the top
10158 // custom: slide the element out to the right with a 2-second duration
10159 el.slideOut('r', { duration: 2 });
10161 // common config options shown with default values
10169 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10170 * @param {Object} options (optional) Object literal with any of the Fx config options
10171 * @return {Roo.Element} The Element
10173 slideOut : function(anchor, o){
10174 var el = this.getFxEl();
10177 el.queueFx(o, function(){
10179 anchor = anchor || "t";
10181 // restore values after effect
10182 var r = this.getFxRestore();
10184 var b = this.getBox();
10185 // fixed size for slide
10189 var wrap = this.fxWrap(r.pos, o, "visible");
10191 var st = this.dom.style;
10192 st.visibility = "visible";
10193 st.position = "absolute";
10197 var after = function(){
10199 el.setDisplayed(false);
10204 el.fxUnwrap(wrap, r.pos, o);
10206 st.width = r.width;
10207 st.height = r.height;
10212 var a, zero = {to: 0};
10213 switch(anchor.toLowerCase()){
10215 st.left = st.bottom = "0";
10216 a = {height: zero};
10219 st.right = st.top = "0";
10223 st.left = st.top = "0";
10224 a = {width: zero, points: {to:[b.right, b.y]}};
10227 st.left = st.top = "0";
10228 a = {height: zero, points: {to:[b.x, b.bottom]}};
10231 st.right = st.bottom = "0";
10232 a = {width: zero, height: zero};
10235 st.right = st.top = "0";
10236 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10239 st.left = st.top = "0";
10240 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10243 st.left = st.bottom = "0";
10244 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10248 arguments.callee.anim = wrap.fxanim(a,
10258 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10259 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10260 * The element must be removed from the DOM using the 'remove' config option if desired.
10266 // common config options shown with default values
10274 * @param {Object} options (optional) Object literal with any of the Fx config options
10275 * @return {Roo.Element} The Element
10277 puff : function(o){
10278 var el = this.getFxEl();
10281 el.queueFx(o, function(){
10282 this.clearOpacity();
10285 // restore values after effect
10286 var r = this.getFxRestore();
10287 var st = this.dom.style;
10289 var after = function(){
10291 el.setDisplayed(false);
10298 el.setPositioning(r.pos);
10299 st.width = r.width;
10300 st.height = r.height;
10305 var width = this.getWidth();
10306 var height = this.getHeight();
10308 arguments.callee.anim = this.fxanim({
10309 width : {to: this.adjustWidth(width * 2)},
10310 height : {to: this.adjustHeight(height * 2)},
10311 points : {by: [-(width * .5), -(height * .5)]},
10313 fontSize: {to:200, unit: "%"}
10324 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10325 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10326 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10332 // all config options shown with default values
10340 * @param {Object} options (optional) Object literal with any of the Fx config options
10341 * @return {Roo.Element} The Element
10343 switchOff : function(o){
10344 var el = this.getFxEl();
10347 el.queueFx(o, function(){
10348 this.clearOpacity();
10351 // restore values after effect
10352 var r = this.getFxRestore();
10353 var st = this.dom.style;
10355 var after = function(){
10357 el.setDisplayed(false);
10363 el.setPositioning(r.pos);
10364 st.width = r.width;
10365 st.height = r.height;
10370 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10371 this.clearOpacity();
10375 points:{by:[0, this.getHeight() * .5]}
10376 }, o, 'motion', 0.3, 'easeIn', after);
10377 }).defer(100, this);
10384 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10385 * changed using the "attr" config option) and then fading back to the original color. If no original
10386 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10389 // default: highlight background to yellow
10392 // custom: highlight foreground text to blue for 2 seconds
10393 el.highlight("0000ff", { attr: 'color', duration: 2 });
10395 // common config options shown with default values
10396 el.highlight("ffff9c", {
10397 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10398 endColor: (current color) or "ffffff",
10403 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10404 * @param {Object} options (optional) Object literal with any of the Fx config options
10405 * @return {Roo.Element} The Element
10407 highlight : function(color, o){
10408 var el = this.getFxEl();
10411 el.queueFx(o, function(){
10412 color = color || "ffff9c";
10413 attr = o.attr || "backgroundColor";
10415 this.clearOpacity();
10418 var origColor = this.getColor(attr);
10419 var restoreColor = this.dom.style[attr];
10420 endColor = (o.endColor || origColor) || "ffffff";
10422 var after = function(){
10423 el.dom.style[attr] = restoreColor;
10428 a[attr] = {from: color, to: endColor};
10429 arguments.callee.anim = this.fxanim(a,
10439 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10442 // default: a single light blue ripple
10445 // custom: 3 red ripples lasting 3 seconds total
10446 el.frame("ff0000", 3, { duration: 3 });
10448 // common config options shown with default values
10449 el.frame("C3DAF9", 1, {
10450 duration: 1 //duration of entire animation (not each individual ripple)
10451 // Note: Easing is not configurable and will be ignored if included
10454 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10455 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10456 * @param {Object} options (optional) Object literal with any of the Fx config options
10457 * @return {Roo.Element} The Element
10459 frame : function(color, count, o){
10460 var el = this.getFxEl();
10463 el.queueFx(o, function(){
10464 color = color || "#C3DAF9";
10465 if(color.length == 6){
10466 color = "#" + color;
10468 count = count || 1;
10469 duration = o.duration || 1;
10472 var b = this.getBox();
10473 var animFn = function(){
10474 var proxy = this.createProxy({
10477 visbility:"hidden",
10478 position:"absolute",
10479 "z-index":"35000", // yee haw
10480 border:"0px solid " + color
10483 var scale = Roo.isBorderBox ? 2 : 1;
10485 top:{from:b.y, to:b.y - 20},
10486 left:{from:b.x, to:b.x - 20},
10487 borderWidth:{from:0, to:10},
10488 opacity:{from:1, to:0},
10489 height:{from:b.height, to:(b.height + (20*scale))},
10490 width:{from:b.width, to:(b.width + (20*scale))}
10491 }, duration, function(){
10495 animFn.defer((duration/2)*1000, this);
10506 * Creates a pause before any subsequent queued effects begin. If there are
10507 * no effects queued after the pause it will have no effect.
10512 * @param {Number} seconds The length of time to pause (in seconds)
10513 * @return {Roo.Element} The Element
10515 pause : function(seconds){
10516 var el = this.getFxEl();
10519 el.queueFx(o, function(){
10520 setTimeout(function(){
10522 }, seconds * 1000);
10528 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10529 * using the "endOpacity" config option.
10532 // default: fade in from opacity 0 to 100%
10535 // custom: fade in from opacity 0 to 75% over 2 seconds
10536 el.fadeIn({ endOpacity: .75, duration: 2});
10538 // common config options shown with default values
10540 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 fadeIn : function(o){
10549 var el = this.getFxEl();
10551 el.queueFx(o, function(){
10552 this.setOpacity(0);
10554 this.dom.style.visibility = 'visible';
10555 var to = o.endOpacity || 1;
10556 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10557 o, null, .5, "easeOut", function(){
10559 this.clearOpacity();
10568 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10569 * using the "endOpacity" config option.
10572 // default: fade out from the element's current opacity to 0
10575 // custom: fade out from the element's current opacity to 25% over 2 seconds
10576 el.fadeOut({ endOpacity: .25, duration: 2});
10578 // common config options shown with default values
10580 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10587 * @param {Object} options (optional) Object literal with any of the Fx config options
10588 * @return {Roo.Element} The Element
10590 fadeOut : function(o){
10591 var el = this.getFxEl();
10593 el.queueFx(o, function(){
10594 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10595 o, null, .5, "easeOut", function(){
10596 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10597 this.dom.style.display = "none";
10599 this.dom.style.visibility = "hidden";
10601 this.clearOpacity();
10609 * Animates the transition of an element's dimensions from a starting height/width
10610 * to an ending height/width.
10613 // change height and width to 100x100 pixels
10614 el.scale(100, 100);
10616 // common config options shown with default values. The height and width will default to
10617 // the element's existing values if passed as null.
10620 [element's height], {
10625 * @param {Number} width The new width (pass undefined to keep the original width)
10626 * @param {Number} height The new height (pass undefined to keep the original height)
10627 * @param {Object} options (optional) Object literal with any of the Fx config options
10628 * @return {Roo.Element} The Element
10630 scale : function(w, h, o){
10631 this.shift(Roo.apply({}, o, {
10639 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10640 * Any of these properties not specified in the config object will not be changed. This effect
10641 * requires that at least one new dimension, position or opacity setting must be passed in on
10642 * the config object in order for the function to have any effect.
10645 // slide the element horizontally to x position 200 while changing the height and opacity
10646 el.shift({ x: 200, height: 50, opacity: .8 });
10648 // common config options shown with default values.
10650 width: [element's width],
10651 height: [element's height],
10652 x: [element's x position],
10653 y: [element's y position],
10654 opacity: [element's opacity],
10659 * @param {Object} options Object literal with any of the Fx config options
10660 * @return {Roo.Element} The Element
10662 shift : function(o){
10663 var el = this.getFxEl();
10665 el.queueFx(o, function(){
10666 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10667 if(w !== undefined){
10668 a.width = {to: this.adjustWidth(w)};
10670 if(h !== undefined){
10671 a.height = {to: this.adjustHeight(h)};
10673 if(x !== undefined || y !== undefined){
10675 x !== undefined ? x : this.getX(),
10676 y !== undefined ? y : this.getY()
10679 if(op !== undefined){
10680 a.opacity = {to: op};
10682 if(o.xy !== undefined){
10683 a.points = {to: o.xy};
10685 arguments.callee.anim = this.fxanim(a,
10686 o, 'motion', .35, "easeOut", function(){
10694 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10695 * ending point of the effect.
10698 // default: slide the element downward while fading out
10701 // custom: slide the element out to the right with a 2-second duration
10702 el.ghost('r', { duration: 2 });
10704 // common config options shown with default values
10712 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10713 * @param {Object} options (optional) Object literal with any of the Fx config options
10714 * @return {Roo.Element} The Element
10716 ghost : function(anchor, o){
10717 var el = this.getFxEl();
10720 el.queueFx(o, function(){
10721 anchor = anchor || "b";
10723 // restore values after effect
10724 var r = this.getFxRestore();
10725 var w = this.getWidth(),
10726 h = this.getHeight();
10728 var st = this.dom.style;
10730 var after = function(){
10732 el.setDisplayed(false);
10738 el.setPositioning(r.pos);
10739 st.width = r.width;
10740 st.height = r.height;
10745 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10746 switch(anchor.toLowerCase()){
10773 arguments.callee.anim = this.fxanim(a,
10783 * Ensures that all effects queued after syncFx is called on the element are
10784 * run concurrently. This is the opposite of {@link #sequenceFx}.
10785 * @return {Roo.Element} The Element
10787 syncFx : function(){
10788 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10797 * Ensures that all effects queued after sequenceFx is called on the element are
10798 * run in sequence. This is the opposite of {@link #syncFx}.
10799 * @return {Roo.Element} The Element
10801 sequenceFx : function(){
10802 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10804 concurrent : false,
10811 nextFx : function(){
10812 var ef = this.fxQueue[0];
10819 * Returns true if the element has any effects actively running or queued, else returns false.
10820 * @return {Boolean} True if element has active effects, else false
10822 hasActiveFx : function(){
10823 return this.fxQueue && this.fxQueue[0];
10827 * Stops any running effects and clears the element's internal effects queue if it contains
10828 * any additional effects that haven't started yet.
10829 * @return {Roo.Element} The Element
10831 stopFx : function(){
10832 if(this.hasActiveFx()){
10833 var cur = this.fxQueue[0];
10834 if(cur && cur.anim && cur.anim.isAnimated()){
10835 this.fxQueue = [cur]; // clear out others
10836 cur.anim.stop(true);
10843 beforeFx : function(o){
10844 if(this.hasActiveFx() && !o.concurrent){
10855 * Returns true if the element is currently blocking so that no other effect can be queued
10856 * until this effect is finished, else returns false if blocking is not set. This is commonly
10857 * used to ensure that an effect initiated by a user action runs to completion prior to the
10858 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10859 * @return {Boolean} True if blocking, else false
10861 hasFxBlock : function(){
10862 var q = this.fxQueue;
10863 return q && q[0] && q[0].block;
10867 queueFx : function(o, fn){
10871 if(!this.hasFxBlock()){
10872 Roo.applyIf(o, this.fxDefaults);
10874 var run = this.beforeFx(o);
10875 fn.block = o.block;
10876 this.fxQueue.push(fn);
10888 fxWrap : function(pos, o, vis){
10890 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10893 wrapXY = this.getXY();
10895 var div = document.createElement("div");
10896 div.style.visibility = vis;
10897 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10898 wrap.setPositioning(pos);
10899 if(wrap.getStyle("position") == "static"){
10900 wrap.position("relative");
10902 this.clearPositioning('auto');
10904 wrap.dom.appendChild(this.dom);
10906 wrap.setXY(wrapXY);
10913 fxUnwrap : function(wrap, pos, o){
10914 this.clearPositioning();
10915 this.setPositioning(pos);
10917 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10923 getFxRestore : function(){
10924 var st = this.dom.style;
10925 return {pos: this.getPositioning(), width: st.width, height : st.height};
10929 afterFx : function(o){
10931 this.applyStyles(o.afterStyle);
10934 this.addClass(o.afterCls);
10936 if(o.remove === true){
10939 Roo.callback(o.callback, o.scope, [this]);
10941 this.fxQueue.shift();
10947 getFxEl : function(){ // support for composite element fx
10948 return Roo.get(this.dom);
10952 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10953 animType = animType || 'run';
10955 var anim = Roo.lib.Anim[animType](
10957 (opt.duration || defaultDur) || .35,
10958 (opt.easing || defaultEase) || 'easeOut',
10960 Roo.callback(cb, this);
10969 // backwords compat
10970 Roo.Fx.resize = Roo.Fx.scale;
10972 //When included, Roo.Fx is automatically applied to Element so that all basic
10973 //effects are available directly via the Element API
10974 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10976 * Ext JS Library 1.1.1
10977 * Copyright(c) 2006-2007, Ext JS, LLC.
10979 * Originally Released Under LGPL - original licence link has changed is not relivant.
10982 * <script type="text/javascript">
10987 * @class Roo.CompositeElement
10988 * Standard composite class. Creates a Roo.Element for every element in the collection.
10990 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10991 * actions will be performed on all the elements in this collection.</b>
10993 * All methods return <i>this</i> and can be chained.
10995 var els = Roo.select("#some-el div.some-class", true);
10996 // or select directly from an existing element
10997 var el = Roo.get('some-el');
10998 el.select('div.some-class', true);
11000 els.setWidth(100); // all elements become 100 width
11001 els.hide(true); // all elements fade out and hide
11003 els.setWidth(100).hide(true);
11006 Roo.CompositeElement = function(els){
11007 this.elements = [];
11008 this.addElements(els);
11010 Roo.CompositeElement.prototype = {
11012 addElements : function(els){
11016 if(typeof els == "string"){
11017 els = Roo.Element.selectorFunction(els);
11019 var yels = this.elements;
11020 var index = yels.length-1;
11021 for(var i = 0, len = els.length; i < len; i++) {
11022 yels[++index] = Roo.get(els[i]);
11028 * Clears this composite and adds the elements returned by the passed selector.
11029 * @param {String/Array} els A string CSS selector, an array of elements or an element
11030 * @return {CompositeElement} this
11032 fill : function(els){
11033 this.elements = [];
11039 * Filters this composite to only elements that match the passed selector.
11040 * @param {String} selector A string CSS selector
11041 * @param {Boolean} inverse return inverse filter (not matches)
11042 * @return {CompositeElement} this
11044 filter : function(selector, inverse){
11046 inverse = inverse || false;
11047 this.each(function(el){
11048 var match = inverse ? !el.is(selector) : el.is(selector);
11050 els[els.length] = el.dom;
11057 invoke : function(fn, args){
11058 var els = this.elements;
11059 for(var i = 0, len = els.length; i < len; i++) {
11060 Roo.Element.prototype[fn].apply(els[i], args);
11065 * Adds elements to this composite.
11066 * @param {String/Array} els A string CSS selector, an array of elements or an element
11067 * @return {CompositeElement} this
11069 add : function(els){
11070 if(typeof els == "string"){
11071 this.addElements(Roo.Element.selectorFunction(els));
11072 }else if(els.length !== undefined){
11073 this.addElements(els);
11075 this.addElements([els]);
11080 * Calls the passed function passing (el, this, index) for each element in this composite.
11081 * @param {Function} fn The function to call
11082 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11083 * @return {CompositeElement} this
11085 each : function(fn, scope){
11086 var els = this.elements;
11087 for(var i = 0, len = els.length; i < len; i++){
11088 if(fn.call(scope || els[i], els[i], this, i) === false) {
11096 * Returns the Element object at the specified index
11097 * @param {Number} index
11098 * @return {Roo.Element}
11100 item : function(index){
11101 return this.elements[index] || null;
11105 * Returns the first Element
11106 * @return {Roo.Element}
11108 first : function(){
11109 return this.item(0);
11113 * Returns the last Element
11114 * @return {Roo.Element}
11117 return this.item(this.elements.length-1);
11121 * Returns the number of elements in this composite
11124 getCount : function(){
11125 return this.elements.length;
11129 * Returns true if this composite contains the passed element
11132 contains : function(el){
11133 return this.indexOf(el) !== -1;
11137 * Returns true if this composite contains the passed element
11140 indexOf : function(el){
11141 return this.elements.indexOf(Roo.get(el));
11146 * Removes the specified element(s).
11147 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11148 * or an array of any of those.
11149 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11150 * @return {CompositeElement} this
11152 removeElement : function(el, removeDom){
11153 if(el instanceof Array){
11154 for(var i = 0, len = el.length; i < len; i++){
11155 this.removeElement(el[i]);
11159 var index = typeof el == 'number' ? el : this.indexOf(el);
11162 var d = this.elements[index];
11166 d.parentNode.removeChild(d);
11169 this.elements.splice(index, 1);
11175 * Replaces the specified element with the passed element.
11176 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11178 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11179 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11180 * @return {CompositeElement} this
11182 replaceElement : function(el, replacement, domReplace){
11183 var index = typeof el == 'number' ? el : this.indexOf(el);
11186 this.elements[index].replaceWith(replacement);
11188 this.elements.splice(index, 1, Roo.get(replacement))
11195 * Removes all elements.
11197 clear : function(){
11198 this.elements = [];
11202 Roo.CompositeElement.createCall = function(proto, fnName){
11203 if(!proto[fnName]){
11204 proto[fnName] = function(){
11205 return this.invoke(fnName, arguments);
11209 for(var fnName in Roo.Element.prototype){
11210 if(typeof Roo.Element.prototype[fnName] == "function"){
11211 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11217 * Ext JS Library 1.1.1
11218 * Copyright(c) 2006-2007, Ext JS, LLC.
11220 * Originally Released Under LGPL - original licence link has changed is not relivant.
11223 * <script type="text/javascript">
11227 * @class Roo.CompositeElementLite
11228 * @extends Roo.CompositeElement
11229 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11231 var els = Roo.select("#some-el div.some-class");
11232 // or select directly from an existing element
11233 var el = Roo.get('some-el');
11234 el.select('div.some-class');
11236 els.setWidth(100); // all elements become 100 width
11237 els.hide(true); // all elements fade out and hide
11239 els.setWidth(100).hide(true);
11240 </code></pre><br><br>
11241 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11242 * actions will be performed on all the elements in this collection.</b>
11244 Roo.CompositeElementLite = function(els){
11245 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11246 this.el = new Roo.Element.Flyweight();
11248 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11249 addElements : function(els){
11251 if(els instanceof Array){
11252 this.elements = this.elements.concat(els);
11254 var yels = this.elements;
11255 var index = yels.length-1;
11256 for(var i = 0, len = els.length; i < len; i++) {
11257 yels[++index] = els[i];
11263 invoke : function(fn, args){
11264 var els = this.elements;
11266 for(var i = 0, len = els.length; i < len; i++) {
11268 Roo.Element.prototype[fn].apply(el, args);
11273 * Returns a flyweight Element of the dom element object at the specified index
11274 * @param {Number} index
11275 * @return {Roo.Element}
11277 item : function(index){
11278 if(!this.elements[index]){
11281 this.el.dom = this.elements[index];
11285 // fixes scope with flyweight
11286 addListener : function(eventName, handler, scope, opt){
11287 var els = this.elements;
11288 for(var i = 0, len = els.length; i < len; i++) {
11289 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11295 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11296 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11297 * a reference to the dom node, use el.dom.</b>
11298 * @param {Function} fn The function to call
11299 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11300 * @return {CompositeElement} this
11302 each : function(fn, scope){
11303 var els = this.elements;
11305 for(var i = 0, len = els.length; i < len; i++){
11307 if(fn.call(scope || el, el, this, i) === false){
11314 indexOf : function(el){
11315 return this.elements.indexOf(Roo.getDom(el));
11318 replaceElement : function(el, replacement, domReplace){
11319 var index = typeof el == 'number' ? el : this.indexOf(el);
11321 replacement = Roo.getDom(replacement);
11323 var d = this.elements[index];
11324 d.parentNode.insertBefore(replacement, d);
11325 d.parentNode.removeChild(d);
11327 this.elements.splice(index, 1, replacement);
11332 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11336 * Ext JS Library 1.1.1
11337 * Copyright(c) 2006-2007, Ext JS, LLC.
11339 * Originally Released Under LGPL - original licence link has changed is not relivant.
11342 * <script type="text/javascript">
11348 * @class Roo.data.Connection
11349 * @extends Roo.util.Observable
11350 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11351 * either to a configured URL, or to a URL specified at request time.<br><br>
11353 * Requests made by this class are asynchronous, and will return immediately. No data from
11354 * the server will be available to the statement immediately following the {@link #request} call.
11355 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11357 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11358 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11359 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11360 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11361 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11362 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11363 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11364 * standard DOM methods.
11366 * @param {Object} config a configuration object.
11368 Roo.data.Connection = function(config){
11369 Roo.apply(this, config);
11372 * @event beforerequest
11373 * Fires before a network request is made to retrieve a data object.
11374 * @param {Connection} conn This Connection object.
11375 * @param {Object} options The options config object passed to the {@link #request} method.
11377 "beforerequest" : true,
11379 * @event requestcomplete
11380 * Fires if the request was successfully completed.
11381 * @param {Connection} conn This Connection object.
11382 * @param {Object} response The XHR object containing the response data.
11383 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11384 * @param {Object} options The options config object passed to the {@link #request} method.
11386 "requestcomplete" : true,
11388 * @event requestexception
11389 * Fires if an error HTTP status was returned from the server.
11390 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11391 * @param {Connection} conn This Connection object.
11392 * @param {Object} response The XHR object containing the response data.
11393 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11394 * @param {Object} options The options config object passed to the {@link #request} method.
11396 "requestexception" : true
11398 Roo.data.Connection.superclass.constructor.call(this);
11401 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11403 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11406 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11407 * extra parameters to each request made by this object. (defaults to undefined)
11410 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11411 * to each request made by this object. (defaults to undefined)
11414 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11417 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11421 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11427 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11430 disableCaching: true,
11433 * Sends an HTTP request to a remote server.
11434 * @param {Object} options An object which may contain the following properties:<ul>
11435 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11436 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11437 * request, a url encoded string or a function to call to get either.</li>
11438 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11439 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11440 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11441 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11442 * <li>options {Object} The parameter to the request call.</li>
11443 * <li>success {Boolean} True if the request succeeded.</li>
11444 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11446 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11447 * The callback is passed the following parameters:<ul>
11448 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11449 * <li>options {Object} The parameter to the request call.</li>
11451 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11452 * The callback is passed the following parameters:<ul>
11453 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11454 * <li>options {Object} The parameter to the request call.</li>
11456 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11457 * for the callback function. Defaults to the browser window.</li>
11458 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11459 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11460 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11461 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11462 * params for the post data. Any params will be appended to the URL.</li>
11463 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11465 * @return {Number} transactionId
11467 request : function(o){
11468 if(this.fireEvent("beforerequest", this, o) !== false){
11471 if(typeof p == "function"){
11472 p = p.call(o.scope||window, o);
11474 if(typeof p == "object"){
11475 p = Roo.urlEncode(o.params);
11477 if(this.extraParams){
11478 var extras = Roo.urlEncode(this.extraParams);
11479 p = p ? (p + '&' + extras) : extras;
11482 var url = o.url || this.url;
11483 if(typeof url == 'function'){
11484 url = url.call(o.scope||window, o);
11488 var form = Roo.getDom(o.form);
11489 url = url || form.action;
11491 var enctype = form.getAttribute("enctype");
11492 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11493 return this.doFormUpload(o, p, url);
11495 var f = Roo.lib.Ajax.serializeForm(form);
11496 p = p ? (p + '&' + f) : f;
11499 var hs = o.headers;
11500 if(this.defaultHeaders){
11501 hs = Roo.apply(hs || {}, this.defaultHeaders);
11508 success: this.handleResponse,
11509 failure: this.handleFailure,
11511 argument: {options: o},
11512 timeout : o.timeout || this.timeout
11515 var method = o.method||this.method||(p ? "POST" : "GET");
11517 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11518 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11521 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11525 }else if(this.autoAbort !== false){
11529 if((method == 'GET' && p) || o.xmlData){
11530 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11533 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11534 return this.transId;
11536 Roo.callback(o.callback, o.scope, [o, null, null]);
11542 * Determine whether this object has a request outstanding.
11543 * @param {Number} transactionId (Optional) defaults to the last transaction
11544 * @return {Boolean} True if there is an outstanding request.
11546 isLoading : function(transId){
11548 return Roo.lib.Ajax.isCallInProgress(transId);
11550 return this.transId ? true : false;
11555 * Aborts any outstanding request.
11556 * @param {Number} transactionId (Optional) defaults to the last transaction
11558 abort : function(transId){
11559 if(transId || this.isLoading()){
11560 Roo.lib.Ajax.abort(transId || this.transId);
11565 handleResponse : function(response){
11566 this.transId = false;
11567 var options = response.argument.options;
11568 response.argument = options ? options.argument : null;
11569 this.fireEvent("requestcomplete", this, response, options);
11570 Roo.callback(options.success, options.scope, [response, options]);
11571 Roo.callback(options.callback, options.scope, [options, true, response]);
11575 handleFailure : function(response, e){
11576 this.transId = false;
11577 var options = response.argument.options;
11578 response.argument = options ? options.argument : null;
11579 this.fireEvent("requestexception", this, response, options, e);
11580 Roo.callback(options.failure, options.scope, [response, options]);
11581 Roo.callback(options.callback, options.scope, [options, false, response]);
11585 doFormUpload : function(o, ps, url){
11587 var frame = document.createElement('iframe');
11590 frame.className = 'x-hidden';
11592 frame.src = Roo.SSL_SECURE_URL;
11594 document.body.appendChild(frame);
11597 document.frames[id].name = id;
11600 var form = Roo.getDom(o.form);
11602 form.method = 'POST';
11603 form.enctype = form.encoding = 'multipart/form-data';
11609 if(ps){ // add dynamic params
11611 ps = Roo.urlDecode(ps, false);
11613 if(ps.hasOwnProperty(k)){
11614 hd = document.createElement('input');
11615 hd.type = 'hidden';
11618 form.appendChild(hd);
11625 var r = { // bogus response object
11630 r.argument = o ? o.argument : null;
11635 doc = frame.contentWindow.document;
11637 doc = (frame.contentDocument || window.frames[id].document);
11639 if(doc && doc.body){
11640 r.responseText = doc.body.innerHTML;
11642 if(doc && doc.XMLDocument){
11643 r.responseXML = doc.XMLDocument;
11645 r.responseXML = doc;
11652 Roo.EventManager.removeListener(frame, 'load', cb, this);
11654 this.fireEvent("requestcomplete", this, r, o);
11655 Roo.callback(o.success, o.scope, [r, o]);
11656 Roo.callback(o.callback, o.scope, [o, true, r]);
11658 setTimeout(function(){document.body.removeChild(frame);}, 100);
11661 Roo.EventManager.on(frame, 'load', cb, this);
11664 if(hiddens){ // remove dynamic params
11665 for(var i = 0, len = hiddens.length; i < len; i++){
11666 form.removeChild(hiddens[i]);
11673 * Ext JS Library 1.1.1
11674 * Copyright(c) 2006-2007, Ext JS, LLC.
11676 * Originally Released Under LGPL - original licence link has changed is not relivant.
11679 * <script type="text/javascript">
11683 * Global Ajax request class.
11686 * @extends Roo.data.Connection
11689 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11690 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11691 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11692 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11693 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11694 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11695 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11697 Roo.Ajax = new Roo.data.Connection({
11706 * Serialize the passed form into a url encoded string
11708 * @param {String/HTMLElement} form
11711 serializeForm : function(form){
11712 return Roo.lib.Ajax.serializeForm(form);
11716 * Ext JS Library 1.1.1
11717 * Copyright(c) 2006-2007, Ext JS, LLC.
11719 * Originally Released Under LGPL - original licence link has changed is not relivant.
11722 * <script type="text/javascript">
11727 * @class Roo.UpdateManager
11728 * @extends Roo.util.Observable
11729 * Provides AJAX-style update for Element object.<br><br>
11732 * // Get it from a Roo.Element object
11733 * var el = Roo.get("foo");
11734 * var mgr = el.getUpdateManager();
11735 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11737 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11739 * // or directly (returns the same UpdateManager instance)
11740 * var mgr = new Roo.UpdateManager("myElementId");
11741 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11742 * mgr.on("update", myFcnNeedsToKnow);
11744 // short handed call directly from the element object
11745 Roo.get("foo").load({
11749 text: "Loading Foo..."
11753 * Create new UpdateManager directly.
11754 * @param {String/HTMLElement/Roo.Element} el The element to update
11755 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11757 Roo.UpdateManager = function(el, forceNew){
11759 if(!forceNew && el.updateManager){
11760 return el.updateManager;
11763 * The Element object
11764 * @type Roo.Element
11768 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11771 this.defaultUrl = null;
11775 * @event beforeupdate
11776 * Fired before an update is made, return false from your handler and the update is cancelled.
11777 * @param {Roo.Element} el
11778 * @param {String/Object/Function} url
11779 * @param {String/Object} params
11781 "beforeupdate": true,
11784 * Fired after successful update is made.
11785 * @param {Roo.Element} el
11786 * @param {Object} oResponseObject The response Object
11791 * Fired on update failure.
11792 * @param {Roo.Element} el
11793 * @param {Object} oResponseObject The response Object
11797 var d = Roo.UpdateManager.defaults;
11799 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11802 this.sslBlankUrl = d.sslBlankUrl;
11804 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11807 this.disableCaching = d.disableCaching;
11809 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11812 this.indicatorText = d.indicatorText;
11814 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11817 this.showLoadIndicator = d.showLoadIndicator;
11819 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11822 this.timeout = d.timeout;
11825 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11828 this.loadScripts = d.loadScripts;
11831 * Transaction object of current executing transaction
11833 this.transaction = null;
11838 this.autoRefreshProcId = null;
11840 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11843 this.refreshDelegate = this.refresh.createDelegate(this);
11845 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11848 this.updateDelegate = this.update.createDelegate(this);
11850 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11853 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11857 this.successDelegate = this.processSuccess.createDelegate(this);
11861 this.failureDelegate = this.processFailure.createDelegate(this);
11863 if(!this.renderer){
11865 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11867 this.renderer = new Roo.UpdateManager.BasicRenderer();
11870 Roo.UpdateManager.superclass.constructor.call(this);
11873 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11875 * Get the Element this UpdateManager is bound to
11876 * @return {Roo.Element} The element
11878 getEl : function(){
11882 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11883 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11886 url: "your-url.php",<br/>
11887 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11888 callback: yourFunction,<br/>
11889 scope: yourObject, //(optional scope) <br/>
11890 discardUrl: false, <br/>
11891 nocache: false,<br/>
11892 text: "Loading...",<br/>
11894 scripts: false<br/>
11897 * The only required property is url. The optional properties nocache, text and scripts
11898 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11899 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11900 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11901 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11903 update : function(url, params, callback, discardUrl){
11904 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11905 var method = this.method,
11907 if(typeof url == "object"){ // must be config object
11910 params = params || cfg.params;
11911 callback = callback || cfg.callback;
11912 discardUrl = discardUrl || cfg.discardUrl;
11913 if(callback && cfg.scope){
11914 callback = callback.createDelegate(cfg.scope);
11916 if(typeof cfg.method != "undefined"){method = cfg.method;};
11917 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11918 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11919 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11920 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11922 this.showLoading();
11924 this.defaultUrl = url;
11926 if(typeof url == "function"){
11927 url = url.call(this);
11930 method = method || (params ? "POST" : "GET");
11931 if(method == "GET"){
11932 url = this.prepareUrl(url);
11935 var o = Roo.apply(cfg ||{}, {
11938 success: this.successDelegate,
11939 failure: this.failureDelegate,
11940 callback: undefined,
11941 timeout: (this.timeout*1000),
11942 argument: {"url": url, "form": null, "callback": callback, "params": params}
11944 Roo.log("updated manager called with timeout of " + o.timeout);
11945 this.transaction = Roo.Ajax.request(o);
11950 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11951 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11952 * @param {String/HTMLElement} form The form Id or form element
11953 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11954 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11955 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11957 formUpdate : function(form, url, reset, callback){
11958 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11959 if(typeof url == "function"){
11960 url = url.call(this);
11962 form = Roo.getDom(form);
11963 this.transaction = Roo.Ajax.request({
11966 success: this.successDelegate,
11967 failure: this.failureDelegate,
11968 timeout: (this.timeout*1000),
11969 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11971 this.showLoading.defer(1, this);
11976 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11977 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11979 refresh : function(callback){
11980 if(this.defaultUrl == null){
11983 this.update(this.defaultUrl, null, callback, true);
11987 * Set this element to auto refresh.
11988 * @param {Number} interval How often to update (in seconds).
11989 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11990 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11991 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11992 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11994 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11996 this.update(url || this.defaultUrl, params, callback, true);
11998 if(this.autoRefreshProcId){
11999 clearInterval(this.autoRefreshProcId);
12001 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12005 * Stop auto refresh on this element.
12007 stopAutoRefresh : function(){
12008 if(this.autoRefreshProcId){
12009 clearInterval(this.autoRefreshProcId);
12010 delete this.autoRefreshProcId;
12014 isAutoRefreshing : function(){
12015 return this.autoRefreshProcId ? true : false;
12018 * Called to update the element to "Loading" state. Override to perform custom action.
12020 showLoading : function(){
12021 if(this.showLoadIndicator){
12022 this.el.update(this.indicatorText);
12027 * Adds unique parameter to query string if disableCaching = true
12030 prepareUrl : function(url){
12031 if(this.disableCaching){
12032 var append = "_dc=" + (new Date().getTime());
12033 if(url.indexOf("?") !== -1){
12034 url += "&" + append;
12036 url += "?" + append;
12045 processSuccess : function(response){
12046 this.transaction = null;
12047 if(response.argument.form && response.argument.reset){
12048 try{ // put in try/catch since some older FF releases had problems with this
12049 response.argument.form.reset();
12052 if(this.loadScripts){
12053 this.renderer.render(this.el, response, this,
12054 this.updateComplete.createDelegate(this, [response]));
12056 this.renderer.render(this.el, response, this);
12057 this.updateComplete(response);
12061 updateComplete : function(response){
12062 this.fireEvent("update", this.el, response);
12063 if(typeof response.argument.callback == "function"){
12064 response.argument.callback(this.el, true, response);
12071 processFailure : function(response){
12072 this.transaction = null;
12073 this.fireEvent("failure", this.el, response);
12074 if(typeof response.argument.callback == "function"){
12075 response.argument.callback(this.el, false, response);
12080 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12081 * @param {Object} renderer The object implementing the render() method
12083 setRenderer : function(renderer){
12084 this.renderer = renderer;
12087 getRenderer : function(){
12088 return this.renderer;
12092 * Set the defaultUrl used for updates
12093 * @param {String/Function} defaultUrl The url or a function to call to get the url
12095 setDefaultUrl : function(defaultUrl){
12096 this.defaultUrl = defaultUrl;
12100 * Aborts the executing transaction
12102 abort : function(){
12103 if(this.transaction){
12104 Roo.Ajax.abort(this.transaction);
12109 * Returns true if an update is in progress
12110 * @return {Boolean}
12112 isUpdating : function(){
12113 if(this.transaction){
12114 return Roo.Ajax.isLoading(this.transaction);
12121 * @class Roo.UpdateManager.defaults
12122 * @static (not really - but it helps the doc tool)
12123 * The defaults collection enables customizing the default properties of UpdateManager
12125 Roo.UpdateManager.defaults = {
12127 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12133 * True to process scripts by default (Defaults to false).
12136 loadScripts : false,
12139 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12142 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12144 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12147 disableCaching : false,
12149 * Whether to show indicatorText when loading (Defaults to true).
12152 showLoadIndicator : true,
12154 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12157 indicatorText : '<div class="loading-indicator">Loading...</div>'
12161 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12163 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12164 * @param {String/HTMLElement/Roo.Element} el The element to update
12165 * @param {String} url The url
12166 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12167 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12170 * @member Roo.UpdateManager
12172 Roo.UpdateManager.updateElement = function(el, url, params, options){
12173 var um = Roo.get(el, true).getUpdateManager();
12174 Roo.apply(um, options);
12175 um.update(url, params, options ? options.callback : null);
12177 // alias for backwards compat
12178 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12180 * @class Roo.UpdateManager.BasicRenderer
12181 * Default Content renderer. Updates the elements innerHTML with the responseText.
12183 Roo.UpdateManager.BasicRenderer = function(){};
12185 Roo.UpdateManager.BasicRenderer.prototype = {
12187 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12188 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12189 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12190 * @param {Roo.Element} el The element being rendered
12191 * @param {Object} response The YUI Connect response object
12192 * @param {UpdateManager} updateManager The calling update manager
12193 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12195 render : function(el, response, updateManager, callback){
12196 el.update(response.responseText, updateManager.loadScripts, callback);
12202 * (c)) Alan Knowles
12208 * @class Roo.DomTemplate
12209 * @extends Roo.Template
12210 * An effort at a dom based template engine..
12212 * Similar to XTemplate, except it uses dom parsing to create the template..
12214 * Supported features:
12219 {a_variable} - output encoded.
12220 {a_variable.format:("Y-m-d")} - call a method on the variable
12221 {a_variable:raw} - unencoded output
12222 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12223 {a_variable:this.method_on_template(...)} - call a method on the template object.
12228 <div roo-for="a_variable or condition.."></div>
12229 <div roo-if="a_variable or condition"></div>
12230 <div roo-exec="some javascript"></div>
12231 <div roo-name="named_template"></div>
12236 Roo.DomTemplate = function()
12238 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12245 Roo.extend(Roo.DomTemplate, Roo.Template, {
12247 * id counter for sub templates.
12251 * flag to indicate if dom parser is inside a pre,
12252 * it will strip whitespace if not.
12257 * The various sub templates
12265 * basic tag replacing syntax
12268 * // you can fake an object call by doing this
12272 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12273 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12275 iterChild : function (node, method) {
12277 var oldPre = this.inPre;
12278 if (node.tagName == 'PRE') {
12281 for( var i = 0; i < node.childNodes.length; i++) {
12282 method.call(this, node.childNodes[i]);
12284 this.inPre = oldPre;
12290 * compile the template
12292 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12295 compile: function()
12299 // covert the html into DOM...
12303 doc = document.implementation.createHTMLDocument("");
12304 doc.documentElement.innerHTML = this.html ;
12305 div = doc.documentElement;
12307 // old IE... - nasty -- it causes all sorts of issues.. with
12308 // images getting pulled from server..
12309 div = document.createElement('div');
12310 div.innerHTML = this.html;
12312 //doc.documentElement.innerHTML = htmlBody
12318 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12320 var tpls = this.tpls;
12322 // create a top level template from the snippet..
12324 //Roo.log(div.innerHTML);
12331 body : div.innerHTML,
12344 Roo.each(tpls, function(tp){
12345 this.compileTpl(tp);
12346 this.tpls[tp.id] = tp;
12349 this.master = tpls[0];
12355 compileNode : function(node, istop) {
12360 // skip anything not a tag..
12361 if (node.nodeType != 1) {
12362 if (node.nodeType == 3 && !this.inPre) {
12363 // reduce white space..
12364 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12387 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12388 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12389 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12390 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12396 // just itterate children..
12397 this.iterChild(node,this.compileNode);
12400 tpl.uid = this.id++;
12401 tpl.value = node.getAttribute('roo-' + tpl.attr);
12402 node.removeAttribute('roo-'+ tpl.attr);
12403 if (tpl.attr != 'name') {
12404 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12405 node.parentNode.replaceChild(placeholder, node);
12408 var placeholder = document.createElement('span');
12409 placeholder.className = 'roo-tpl-' + tpl.value;
12410 node.parentNode.replaceChild(placeholder, node);
12413 // parent now sees '{domtplXXXX}
12414 this.iterChild(node,this.compileNode);
12416 // we should now have node body...
12417 var div = document.createElement('div');
12418 div.appendChild(node);
12420 // this has the unfortunate side effect of converting tagged attributes
12421 // eg. href="{...}" into %7C...%7D
12422 // this has been fixed by searching for those combo's although it's a bit hacky..
12425 tpl.body = div.innerHTML;
12432 switch (tpl.value) {
12433 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12434 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12435 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12440 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12444 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12448 tpl.id = tpl.value; // replace non characters???
12454 this.tpls.push(tpl);
12464 * Compile a segment of the template into a 'sub-template'
12470 compileTpl : function(tpl)
12472 var fm = Roo.util.Format;
12473 var useF = this.disableFormats !== true;
12475 var sep = Roo.isGecko ? "+\n" : ",\n";
12477 var undef = function(str) {
12478 Roo.debug && Roo.log("Property not found :" + str);
12482 //Roo.log(tpl.body);
12486 var fn = function(m, lbrace, name, format, args)
12489 //Roo.log(arguments);
12490 args = args ? args.replace(/\\'/g,"'") : args;
12491 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12492 if (typeof(format) == 'undefined') {
12493 format = 'htmlEncode';
12495 if (format == 'raw' ) {
12499 if(name.substr(0, 6) == 'domtpl'){
12500 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12503 // build an array of options to determine if value is undefined..
12505 // basically get 'xxxx.yyyy' then do
12506 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12507 // (function () { Roo.log("Property not found"); return ''; })() :
12512 Roo.each(name.split('.'), function(st) {
12513 lookfor += (lookfor.length ? '.': '') + st;
12514 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12517 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12520 if(format && useF){
12522 args = args ? ',' + args : "";
12524 if(format.substr(0, 5) != "this."){
12525 format = "fm." + format + '(';
12527 format = 'this.call("'+ format.substr(5) + '", ';
12531 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12534 if (args && args.length) {
12535 // called with xxyx.yuu:(test,test)
12537 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12539 // raw.. - :raw modifier..
12540 return "'"+ sep + udef_st + name + ")"+sep+"'";
12544 // branched to use + in gecko and [].join() in others
12546 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12547 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12550 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12551 body.push(tpl.body.replace(/(\r\n|\n)/g,
12552 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12553 body.push("'].join('');};};");
12554 body = body.join('');
12557 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12559 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12566 * same as applyTemplate, except it's done to one of the subTemplates
12567 * when using named templates, you can do:
12569 * var str = pl.applySubTemplate('your-name', values);
12572 * @param {Number} id of the template
12573 * @param {Object} values to apply to template
12574 * @param {Object} parent (normaly the instance of this object)
12576 applySubTemplate : function(id, values, parent)
12580 var t = this.tpls[id];
12584 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12585 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12589 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12596 if(t.execCall && t.execCall.call(this, values, parent)){
12600 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12606 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12607 parent = t.target ? values : parent;
12608 if(t.forCall && vs instanceof Array){
12610 for(var i = 0, len = vs.length; i < len; i++){
12612 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12614 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12616 //Roo.log(t.compiled);
12620 return buf.join('');
12623 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12628 return t.compiled.call(this, vs, parent);
12630 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12632 //Roo.log(t.compiled);
12640 applyTemplate : function(values){
12641 return this.master.compiled.call(this, values, {});
12642 //var s = this.subs;
12645 apply : function(){
12646 return this.applyTemplate.apply(this, arguments);
12651 Roo.DomTemplate.from = function(el){
12652 el = Roo.getDom(el);
12653 return new Roo.Domtemplate(el.value || el.innerHTML);
12656 * Ext JS Library 1.1.1
12657 * Copyright(c) 2006-2007, Ext JS, LLC.
12659 * Originally Released Under LGPL - original licence link has changed is not relivant.
12662 * <script type="text/javascript">
12666 * @class Roo.util.DelayedTask
12667 * Provides a convenient method of performing setTimeout where a new
12668 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12669 * You can use this class to buffer
12670 * the keypress events for a certain number of milliseconds, and perform only if they stop
12671 * for that amount of time.
12672 * @constructor The parameters to this constructor serve as defaults and are not required.
12673 * @param {Function} fn (optional) The default function to timeout
12674 * @param {Object} scope (optional) The default scope of that timeout
12675 * @param {Array} args (optional) The default Array of arguments
12677 Roo.util.DelayedTask = function(fn, scope, args){
12678 var id = null, d, t;
12680 var call = function(){
12681 var now = new Date().getTime();
12685 fn.apply(scope, args || []);
12689 * Cancels any pending timeout and queues a new one
12690 * @param {Number} delay The milliseconds to delay
12691 * @param {Function} newFn (optional) Overrides function passed to constructor
12692 * @param {Object} newScope (optional) Overrides scope passed to constructor
12693 * @param {Array} newArgs (optional) Overrides args passed to constructor
12695 this.delay = function(delay, newFn, newScope, newArgs){
12696 if(id && delay != d){
12700 t = new Date().getTime();
12702 scope = newScope || scope;
12703 args = newArgs || args;
12705 id = setInterval(call, d);
12710 * Cancel the last queued timeout
12712 this.cancel = function(){
12720 * Ext JS Library 1.1.1
12721 * Copyright(c) 2006-2007, Ext JS, LLC.
12723 * Originally Released Under LGPL - original licence link has changed is not relivant.
12726 * <script type="text/javascript">
12730 Roo.util.TaskRunner = function(interval){
12731 interval = interval || 10;
12732 var tasks = [], removeQueue = [];
12734 var running = false;
12736 var stopThread = function(){
12742 var startThread = function(){
12745 id = setInterval(runTasks, interval);
12749 var removeTask = function(task){
12750 removeQueue.push(task);
12756 var runTasks = function(){
12757 if(removeQueue.length > 0){
12758 for(var i = 0, len = removeQueue.length; i < len; i++){
12759 tasks.remove(removeQueue[i]);
12762 if(tasks.length < 1){
12767 var now = new Date().getTime();
12768 for(var i = 0, len = tasks.length; i < len; ++i){
12770 var itime = now - t.taskRunTime;
12771 if(t.interval <= itime){
12772 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12773 t.taskRunTime = now;
12774 if(rt === false || t.taskRunCount === t.repeat){
12779 if(t.duration && t.duration <= (now - t.taskStartTime)){
12786 * Queues a new task.
12787 * @param {Object} task
12789 this.start = function(task){
12791 task.taskStartTime = new Date().getTime();
12792 task.taskRunTime = 0;
12793 task.taskRunCount = 0;
12798 this.stop = function(task){
12803 this.stopAll = function(){
12805 for(var i = 0, len = tasks.length; i < len; i++){
12806 if(tasks[i].onStop){
12815 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12817 * Ext JS Library 1.1.1
12818 * Copyright(c) 2006-2007, Ext JS, LLC.
12820 * Originally Released Under LGPL - original licence link has changed is not relivant.
12823 * <script type="text/javascript">
12828 * @class Roo.util.MixedCollection
12829 * @extends Roo.util.Observable
12830 * A Collection class that maintains both numeric indexes and keys and exposes events.
12832 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12833 * collection (defaults to false)
12834 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12835 * and return the key value for that item. This is used when available to look up the key on items that
12836 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12837 * equivalent to providing an implementation for the {@link #getKey} method.
12839 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12847 * Fires when the collection is cleared.
12852 * Fires when an item is added to the collection.
12853 * @param {Number} index The index at which the item was added.
12854 * @param {Object} o The item added.
12855 * @param {String} key The key associated with the added item.
12860 * Fires when an item is replaced in the collection.
12861 * @param {String} key he key associated with the new added.
12862 * @param {Object} old The item being replaced.
12863 * @param {Object} new The new item.
12868 * Fires when an item is removed from the collection.
12869 * @param {Object} o The item being removed.
12870 * @param {String} key (optional) The key associated with the removed item.
12875 this.allowFunctions = allowFunctions === true;
12877 this.getKey = keyFn;
12879 Roo.util.MixedCollection.superclass.constructor.call(this);
12882 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12883 allowFunctions : false,
12886 * Adds an item to the collection.
12887 * @param {String} key The key to associate with the item
12888 * @param {Object} o The item to add.
12889 * @return {Object} The item added.
12891 add : function(key, o){
12892 if(arguments.length == 1){
12894 key = this.getKey(o);
12896 if(typeof key == "undefined" || key === null){
12898 this.items.push(o);
12899 this.keys.push(null);
12901 var old = this.map[key];
12903 return this.replace(key, o);
12906 this.items.push(o);
12908 this.keys.push(key);
12910 this.fireEvent("add", this.length-1, o, key);
12915 * MixedCollection has a generic way to fetch keys if you implement getKey.
12918 var mc = new Roo.util.MixedCollection();
12919 mc.add(someEl.dom.id, someEl);
12920 mc.add(otherEl.dom.id, otherEl);
12924 var mc = new Roo.util.MixedCollection();
12925 mc.getKey = function(el){
12931 // or via the constructor
12932 var mc = new Roo.util.MixedCollection(false, function(el){
12938 * @param o {Object} The item for which to find the key.
12939 * @return {Object} The key for the passed item.
12941 getKey : function(o){
12946 * Replaces an item in the collection.
12947 * @param {String} key The key associated with the item to replace, or the item to replace.
12948 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12949 * @return {Object} The new item.
12951 replace : function(key, o){
12952 if(arguments.length == 1){
12954 key = this.getKey(o);
12956 var old = this.item(key);
12957 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12958 return this.add(key, o);
12960 var index = this.indexOfKey(key);
12961 this.items[index] = o;
12963 this.fireEvent("replace", key, old, o);
12968 * Adds all elements of an Array or an Object to the collection.
12969 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12970 * an Array of values, each of which are added to the collection.
12972 addAll : function(objs){
12973 if(arguments.length > 1 || objs instanceof Array){
12974 var args = arguments.length > 1 ? arguments : objs;
12975 for(var i = 0, len = args.length; i < len; i++){
12979 for(var key in objs){
12980 if(this.allowFunctions || typeof objs[key] != "function"){
12981 this.add(key, objs[key]);
12988 * Executes the specified function once for every item in the collection, passing each
12989 * item as the first and only parameter. returning false from the function will stop the iteration.
12990 * @param {Function} fn The function to execute for each item.
12991 * @param {Object} scope (optional) The scope in which to execute the function.
12993 each : function(fn, scope){
12994 var items = [].concat(this.items); // each safe for removal
12995 for(var i = 0, len = items.length; i < len; i++){
12996 if(fn.call(scope || items[i], items[i], i, len) === false){
13003 * Executes the specified function once for every key in the collection, passing each
13004 * key, and its associated item as the first two parameters.
13005 * @param {Function} fn The function to execute for each item.
13006 * @param {Object} scope (optional) The scope in which to execute the function.
13008 eachKey : function(fn, scope){
13009 for(var i = 0, len = this.keys.length; i < len; i++){
13010 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13015 * Returns the first item in the collection which elicits a true return value from the
13016 * passed selection function.
13017 * @param {Function} fn The selection function to execute for each item.
13018 * @param {Object} scope (optional) The scope in which to execute the function.
13019 * @return {Object} The first item in the collection which returned true from the selection function.
13021 find : function(fn, scope){
13022 for(var i = 0, len = this.items.length; i < len; i++){
13023 if(fn.call(scope || window, this.items[i], this.keys[i])){
13024 return this.items[i];
13031 * Inserts an item at the specified index in the collection.
13032 * @param {Number} index The index to insert the item at.
13033 * @param {String} key The key to associate with the new item, or the item itself.
13034 * @param {Object} o (optional) If the second parameter was a key, the new item.
13035 * @return {Object} The item inserted.
13037 insert : function(index, key, o){
13038 if(arguments.length == 2){
13040 key = this.getKey(o);
13042 if(index >= this.length){
13043 return this.add(key, o);
13046 this.items.splice(index, 0, o);
13047 if(typeof key != "undefined" && key != null){
13050 this.keys.splice(index, 0, key);
13051 this.fireEvent("add", index, o, key);
13056 * Removed an item from the collection.
13057 * @param {Object} o The item to remove.
13058 * @return {Object} The item removed.
13060 remove : function(o){
13061 return this.removeAt(this.indexOf(o));
13065 * Remove an item from a specified index in the collection.
13066 * @param {Number} index The index within the collection of the item to remove.
13068 removeAt : function(index){
13069 if(index < this.length && index >= 0){
13071 var o = this.items[index];
13072 this.items.splice(index, 1);
13073 var key = this.keys[index];
13074 if(typeof key != "undefined"){
13075 delete this.map[key];
13077 this.keys.splice(index, 1);
13078 this.fireEvent("remove", o, key);
13083 * Removed an item associated with the passed key fom the collection.
13084 * @param {String} key The key of the item to remove.
13086 removeKey : function(key){
13087 return this.removeAt(this.indexOfKey(key));
13091 * Returns the number of items in the collection.
13092 * @return {Number} the number of items in the collection.
13094 getCount : function(){
13095 return this.length;
13099 * Returns index within the collection of the passed Object.
13100 * @param {Object} o The item to find the index of.
13101 * @return {Number} index of the item.
13103 indexOf : function(o){
13104 if(!this.items.indexOf){
13105 for(var i = 0, len = this.items.length; i < len; i++){
13106 if(this.items[i] == o) {
13112 return this.items.indexOf(o);
13117 * Returns index within the collection of the passed key.
13118 * @param {String} key The key to find the index of.
13119 * @return {Number} index of the key.
13121 indexOfKey : function(key){
13122 if(!this.keys.indexOf){
13123 for(var i = 0, len = this.keys.length; i < len; i++){
13124 if(this.keys[i] == key) {
13130 return this.keys.indexOf(key);
13135 * Returns the item associated with the passed key OR index. Key has priority over index.
13136 * @param {String/Number} key The key or index of the item.
13137 * @return {Object} The item associated with the passed key.
13139 item : function(key){
13140 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13141 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13145 * Returns the item at the specified index.
13146 * @param {Number} index The index of the item.
13149 itemAt : function(index){
13150 return this.items[index];
13154 * Returns the item associated with the passed key.
13155 * @param {String/Number} key The key of the item.
13156 * @return {Object} The item associated with the passed key.
13158 key : function(key){
13159 return this.map[key];
13163 * Returns true if the collection contains the passed Object as an item.
13164 * @param {Object} o The Object to look for in the collection.
13165 * @return {Boolean} True if the collection contains the Object as an item.
13167 contains : function(o){
13168 return this.indexOf(o) != -1;
13172 * Returns true if the collection contains the passed Object as a key.
13173 * @param {String} key The key to look for in the collection.
13174 * @return {Boolean} True if the collection contains the Object as a key.
13176 containsKey : function(key){
13177 return typeof this.map[key] != "undefined";
13181 * Removes all items from the collection.
13183 clear : function(){
13188 this.fireEvent("clear");
13192 * Returns the first item in the collection.
13193 * @return {Object} the first item in the collection..
13195 first : function(){
13196 return this.items[0];
13200 * Returns the last item in the collection.
13201 * @return {Object} the last item in the collection..
13204 return this.items[this.length-1];
13207 _sort : function(property, dir, fn){
13208 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13209 fn = fn || function(a, b){
13212 var c = [], k = this.keys, items = this.items;
13213 for(var i = 0, len = items.length; i < len; i++){
13214 c[c.length] = {key: k[i], value: items[i], index: i};
13216 c.sort(function(a, b){
13217 var v = fn(a[property], b[property]) * dsc;
13219 v = (a.index < b.index ? -1 : 1);
13223 for(var i = 0, len = c.length; i < len; i++){
13224 items[i] = c[i].value;
13227 this.fireEvent("sort", this);
13231 * Sorts this collection with the passed comparison function
13232 * @param {String} direction (optional) "ASC" or "DESC"
13233 * @param {Function} fn (optional) comparison function
13235 sort : function(dir, fn){
13236 this._sort("value", dir, fn);
13240 * Sorts this collection by keys
13241 * @param {String} direction (optional) "ASC" or "DESC"
13242 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13244 keySort : function(dir, fn){
13245 this._sort("key", dir, fn || function(a, b){
13246 return String(a).toUpperCase()-String(b).toUpperCase();
13251 * Returns a range of items in this collection
13252 * @param {Number} startIndex (optional) defaults to 0
13253 * @param {Number} endIndex (optional) default to the last item
13254 * @return {Array} An array of items
13256 getRange : function(start, end){
13257 var items = this.items;
13258 if(items.length < 1){
13261 start = start || 0;
13262 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13265 for(var i = start; i <= end; i++) {
13266 r[r.length] = items[i];
13269 for(var i = start; i >= end; i--) {
13270 r[r.length] = items[i];
13277 * Filter the <i>objects</i> in this collection by a specific property.
13278 * Returns a new collection that has been filtered.
13279 * @param {String} property A property on your objects
13280 * @param {String/RegExp} value Either string that the property values
13281 * should start with or a RegExp to test against the property
13282 * @return {MixedCollection} The new filtered collection
13284 filter : function(property, value){
13285 if(!value.exec){ // not a regex
13286 value = String(value);
13287 if(value.length == 0){
13288 return this.clone();
13290 value = new RegExp("^" + Roo.escapeRe(value), "i");
13292 return this.filterBy(function(o){
13293 return o && value.test(o[property]);
13298 * Filter by a function. * Returns a new collection that has been filtered.
13299 * The passed function will be called with each
13300 * object in the collection. If the function returns true, the value is included
13301 * otherwise it is filtered.
13302 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13303 * @param {Object} scope (optional) The scope of the function (defaults to this)
13304 * @return {MixedCollection} The new filtered collection
13306 filterBy : function(fn, scope){
13307 var r = new Roo.util.MixedCollection();
13308 r.getKey = this.getKey;
13309 var k = this.keys, it = this.items;
13310 for(var i = 0, len = it.length; i < len; i++){
13311 if(fn.call(scope||this, it[i], k[i])){
13312 r.add(k[i], it[i]);
13319 * Creates a duplicate of this collection
13320 * @return {MixedCollection}
13322 clone : function(){
13323 var r = new Roo.util.MixedCollection();
13324 var k = this.keys, it = this.items;
13325 for(var i = 0, len = it.length; i < len; i++){
13326 r.add(k[i], it[i]);
13328 r.getKey = this.getKey;
13333 * Returns the item associated with the passed key or index.
13335 * @param {String/Number} key The key or index of the item.
13336 * @return {Object} The item associated with the passed key.
13338 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13340 * Ext JS Library 1.1.1
13341 * Copyright(c) 2006-2007, Ext JS, LLC.
13343 * Originally Released Under LGPL - original licence link has changed is not relivant.
13346 * <script type="text/javascript">
13349 * @class Roo.util.JSON
13350 * Modified version of Douglas Crockford"s json.js that doesn"t
13351 * mess with the Object prototype
13352 * http://www.json.org/js.html
13355 Roo.util.JSON = new (function(){
13356 var useHasOwn = {}.hasOwnProperty ? true : false;
13358 // crashes Safari in some instances
13359 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13361 var pad = function(n) {
13362 return n < 10 ? "0" + n : n;
13375 var encodeString = function(s){
13376 if (/["\\\x00-\x1f]/.test(s)) {
13377 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13382 c = b.charCodeAt();
13384 Math.floor(c / 16).toString(16) +
13385 (c % 16).toString(16);
13388 return '"' + s + '"';
13391 var encodeArray = function(o){
13392 var a = ["["], b, i, l = o.length, v;
13393 for (i = 0; i < l; i += 1) {
13395 switch (typeof v) {
13404 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13412 var encodeDate = function(o){
13413 return '"' + o.getFullYear() + "-" +
13414 pad(o.getMonth() + 1) + "-" +
13415 pad(o.getDate()) + "T" +
13416 pad(o.getHours()) + ":" +
13417 pad(o.getMinutes()) + ":" +
13418 pad(o.getSeconds()) + '"';
13422 * Encodes an Object, Array or other value
13423 * @param {Mixed} o The variable to encode
13424 * @return {String} The JSON string
13426 this.encode = function(o)
13428 // should this be extended to fully wrap stringify..
13430 if(typeof o == "undefined" || o === null){
13432 }else if(o instanceof Array){
13433 return encodeArray(o);
13434 }else if(o instanceof Date){
13435 return encodeDate(o);
13436 }else if(typeof o == "string"){
13437 return encodeString(o);
13438 }else if(typeof o == "number"){
13439 return isFinite(o) ? String(o) : "null";
13440 }else if(typeof o == "boolean"){
13443 var a = ["{"], b, i, v;
13445 if(!useHasOwn || o.hasOwnProperty(i)) {
13447 switch (typeof v) {
13456 a.push(this.encode(i), ":",
13457 v === null ? "null" : this.encode(v));
13468 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13469 * @param {String} json The JSON string
13470 * @return {Object} The resulting object
13472 this.decode = function(json){
13474 return /** eval:var:json */ eval("(" + json + ')');
13478 * Shorthand for {@link Roo.util.JSON#encode}
13479 * @member Roo encode
13481 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13483 * Shorthand for {@link Roo.util.JSON#decode}
13484 * @member Roo decode
13486 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13489 * Ext JS Library 1.1.1
13490 * Copyright(c) 2006-2007, Ext JS, LLC.
13492 * Originally Released Under LGPL - original licence link has changed is not relivant.
13495 * <script type="text/javascript">
13499 * @class Roo.util.Format
13500 * Reusable data formatting functions
13503 Roo.util.Format = function(){
13504 var trimRe = /^\s+|\s+$/g;
13507 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13508 * @param {String} value The string to truncate
13509 * @param {Number} length The maximum length to allow before truncating
13510 * @return {String} The converted text
13512 ellipsis : function(value, len){
13513 if(value && value.length > len){
13514 return value.substr(0, len-3)+"...";
13520 * Checks a reference and converts it to empty string if it is undefined
13521 * @param {Mixed} value Reference to check
13522 * @return {Mixed} Empty string if converted, otherwise the original value
13524 undef : function(value){
13525 return typeof value != "undefined" ? value : "";
13529 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13530 * @param {String} value The string to encode
13531 * @return {String} The encoded text
13533 htmlEncode : function(value){
13534 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13538 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13539 * @param {String} value The string to decode
13540 * @return {String} The decoded text
13542 htmlDecode : function(value){
13543 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13547 * Trims any whitespace from either side of a string
13548 * @param {String} value The text to trim
13549 * @return {String} The trimmed text
13551 trim : function(value){
13552 return String(value).replace(trimRe, "");
13556 * Returns a substring from within an original string
13557 * @param {String} value The original text
13558 * @param {Number} start The start index of the substring
13559 * @param {Number} length The length of the substring
13560 * @return {String} The substring
13562 substr : function(value, start, length){
13563 return String(value).substr(start, length);
13567 * Converts a string to all lower case letters
13568 * @param {String} value The text to convert
13569 * @return {String} The converted text
13571 lowercase : function(value){
13572 return String(value).toLowerCase();
13576 * Converts a string to all upper case letters
13577 * @param {String} value The text to convert
13578 * @return {String} The converted text
13580 uppercase : function(value){
13581 return String(value).toUpperCase();
13585 * Converts the first character only of a string to upper case
13586 * @param {String} value The text to convert
13587 * @return {String} The converted text
13589 capitalize : function(value){
13590 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13594 call : function(value, fn){
13595 if(arguments.length > 2){
13596 var args = Array.prototype.slice.call(arguments, 2);
13597 args.unshift(value);
13599 return /** eval:var:value */ eval(fn).apply(window, args);
13601 /** eval:var:value */
13602 return /** eval:var:value */ eval(fn).call(window, value);
13608 * safer version of Math.toFixed..??/
13609 * @param {Number/String} value The numeric value to format
13610 * @param {Number/String} value Decimal places
13611 * @return {String} The formatted currency string
13613 toFixed : function(v, n)
13615 // why not use to fixed - precision is buggered???
13617 return Math.round(v-0);
13619 var fact = Math.pow(10,n+1);
13620 v = (Math.round((v-0)*fact))/fact;
13621 var z = (''+fact).substring(2);
13622 if (v == Math.floor(v)) {
13623 return Math.floor(v) + '.' + z;
13626 // now just padd decimals..
13627 var ps = String(v).split('.');
13628 var fd = (ps[1] + z);
13629 var r = fd.substring(0,n);
13630 var rm = fd.substring(n);
13632 return ps[0] + '.' + r;
13634 r*=1; // turn it into a number;
13636 if (String(r).length != n) {
13639 r = String(r).substring(1); // chop the end off.
13642 return ps[0] + '.' + r;
13647 * Format a number as US currency
13648 * @param {Number/String} value The numeric value to format
13649 * @return {String} The formatted currency string
13651 usMoney : function(v){
13652 return '$' + Roo.util.Format.number(v);
13657 * eventually this should probably emulate php's number_format
13658 * @param {Number/String} value The numeric value to format
13659 * @param {Number} decimals number of decimal places
13660 * @return {String} The formatted currency string
13662 number : function(v,decimals)
13664 // multiply and round.
13665 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13666 var mul = Math.pow(10, decimals);
13667 var zero = String(mul).substring(1);
13668 v = (Math.round((v-0)*mul))/mul;
13670 // if it's '0' number.. then
13672 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13674 var ps = v.split('.');
13678 var r = /(\d+)(\d{3})/;
13680 while (r.test(whole)) {
13681 whole = whole.replace(r, '$1' + ',' + '$2');
13687 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13688 // does not have decimals
13689 (decimals ? ('.' + zero) : '');
13692 return whole + sub ;
13696 * Parse a value into a formatted date using the specified format pattern.
13697 * @param {Mixed} value The value to format
13698 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13699 * @return {String} The formatted date string
13701 date : function(v, format){
13705 if(!(v instanceof Date)){
13706 v = new Date(Date.parse(v));
13708 return v.dateFormat(format || Roo.util.Format.defaults.date);
13712 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13713 * @param {String} format Any valid date format string
13714 * @return {Function} The date formatting function
13716 dateRenderer : function(format){
13717 return function(v){
13718 return Roo.util.Format.date(v, format);
13723 stripTagsRE : /<\/?[^>]+>/gi,
13726 * Strips all HTML tags
13727 * @param {Mixed} value The text from which to strip tags
13728 * @return {String} The stripped text
13730 stripTags : function(v){
13731 return !v ? v : String(v).replace(this.stripTagsRE, "");
13735 Roo.util.Format.defaults = {
13739 * Ext JS Library 1.1.1
13740 * Copyright(c) 2006-2007, Ext JS, LLC.
13742 * Originally Released Under LGPL - original licence link has changed is not relivant.
13745 * <script type="text/javascript">
13752 * @class Roo.MasterTemplate
13753 * @extends Roo.Template
13754 * Provides a template that can have child templates. The syntax is:
13756 var t = new Roo.MasterTemplate(
13757 '<select name="{name}">',
13758 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13761 t.add('options', {value: 'foo', text: 'bar'});
13762 // or you can add multiple child elements in one shot
13763 t.addAll('options', [
13764 {value: 'foo', text: 'bar'},
13765 {value: 'foo2', text: 'bar2'},
13766 {value: 'foo3', text: 'bar3'}
13768 // then append, applying the master template values
13769 t.append('my-form', {name: 'my-select'});
13771 * A name attribute for the child template is not required if you have only one child
13772 * template or you want to refer to them by index.
13774 Roo.MasterTemplate = function(){
13775 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13776 this.originalHtml = this.html;
13778 var m, re = this.subTemplateRe;
13781 while(m = re.exec(this.html)){
13782 var name = m[1], content = m[2];
13787 tpl : new Roo.Template(content)
13790 st[name] = st[subIndex];
13792 st[subIndex].tpl.compile();
13793 st[subIndex].tpl.call = this.call.createDelegate(this);
13796 this.subCount = subIndex;
13799 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13801 * The regular expression used to match sub templates
13805 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13808 * Applies the passed values to a child template.
13809 * @param {String/Number} name (optional) The name or index of the child template
13810 * @param {Array/Object} values The values to be applied to the template
13811 * @return {MasterTemplate} this
13813 add : function(name, values){
13814 if(arguments.length == 1){
13815 values = arguments[0];
13818 var s = this.subs[name];
13819 s.buffer[s.buffer.length] = s.tpl.apply(values);
13824 * Applies all the passed values to a child template.
13825 * @param {String/Number} name (optional) The name or index of the child template
13826 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13827 * @param {Boolean} reset (optional) True to reset the template first
13828 * @return {MasterTemplate} this
13830 fill : function(name, values, reset){
13832 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13840 for(var i = 0, len = values.length; i < len; i++){
13841 this.add(name, values[i]);
13847 * Resets the template for reuse
13848 * @return {MasterTemplate} this
13850 reset : function(){
13852 for(var i = 0; i < this.subCount; i++){
13858 applyTemplate : function(values){
13860 var replaceIndex = -1;
13861 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13862 return s[++replaceIndex].buffer.join("");
13864 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13867 apply : function(){
13868 return this.applyTemplate.apply(this, arguments);
13871 compile : function(){return this;}
13875 * Alias for fill().
13878 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13880 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13881 * var tpl = Roo.MasterTemplate.from('element-id');
13882 * @param {String/HTMLElement} el
13883 * @param {Object} config
13886 Roo.MasterTemplate.from = function(el, config){
13887 el = Roo.getDom(el);
13888 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13891 * Ext JS Library 1.1.1
13892 * Copyright(c) 2006-2007, Ext JS, LLC.
13894 * Originally Released Under LGPL - original licence link has changed is not relivant.
13897 * <script type="text/javascript">
13902 * @class Roo.util.CSS
13903 * Utility class for manipulating CSS rules
13906 Roo.util.CSS = function(){
13908 var doc = document;
13910 var camelRe = /(-[a-z])/gi;
13911 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13915 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13916 * tag and appended to the HEAD of the document.
13917 * @param {String|Object} cssText The text containing the css rules
13918 * @param {String} id An id to add to the stylesheet for later removal
13919 * @return {StyleSheet}
13921 createStyleSheet : function(cssText, id){
13923 var head = doc.getElementsByTagName("head")[0];
13924 var nrules = doc.createElement("style");
13925 nrules.setAttribute("type", "text/css");
13927 nrules.setAttribute("id", id);
13929 if (typeof(cssText) != 'string') {
13930 // support object maps..
13931 // not sure if this a good idea..
13932 // perhaps it should be merged with the general css handling
13933 // and handle js style props.
13934 var cssTextNew = [];
13935 for(var n in cssText) {
13937 for(var k in cssText[n]) {
13938 citems.push( k + ' : ' +cssText[n][k] + ';' );
13940 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13943 cssText = cssTextNew.join("\n");
13949 head.appendChild(nrules);
13950 ss = nrules.styleSheet;
13951 ss.cssText = cssText;
13954 nrules.appendChild(doc.createTextNode(cssText));
13956 nrules.cssText = cssText;
13958 head.appendChild(nrules);
13959 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13961 this.cacheStyleSheet(ss);
13966 * Removes a style or link tag by id
13967 * @param {String} id The id of the tag
13969 removeStyleSheet : function(id){
13970 var existing = doc.getElementById(id);
13972 existing.parentNode.removeChild(existing);
13977 * Dynamically swaps an existing stylesheet reference for a new one
13978 * @param {String} id The id of an existing link tag to remove
13979 * @param {String} url The href of the new stylesheet to include
13981 swapStyleSheet : function(id, url){
13982 this.removeStyleSheet(id);
13983 var ss = doc.createElement("link");
13984 ss.setAttribute("rel", "stylesheet");
13985 ss.setAttribute("type", "text/css");
13986 ss.setAttribute("id", id);
13987 ss.setAttribute("href", url);
13988 doc.getElementsByTagName("head")[0].appendChild(ss);
13992 * Refresh the rule cache if you have dynamically added stylesheets
13993 * @return {Object} An object (hash) of rules indexed by selector
13995 refreshCache : function(){
13996 return this.getRules(true);
14000 cacheStyleSheet : function(stylesheet){
14004 try{// try catch for cross domain access issue
14005 var ssRules = stylesheet.cssRules || stylesheet.rules;
14006 for(var j = ssRules.length-1; j >= 0; --j){
14007 rules[ssRules[j].selectorText] = ssRules[j];
14013 * Gets all css rules for the document
14014 * @param {Boolean} refreshCache true to refresh the internal cache
14015 * @return {Object} An object (hash) of rules indexed by selector
14017 getRules : function(refreshCache){
14018 if(rules == null || refreshCache){
14020 var ds = doc.styleSheets;
14021 for(var i =0, len = ds.length; i < len; i++){
14023 this.cacheStyleSheet(ds[i]);
14031 * Gets an an individual CSS rule by selector(s)
14032 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14033 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14034 * @return {CSSRule} The CSS rule or null if one is not found
14036 getRule : function(selector, refreshCache){
14037 var rs = this.getRules(refreshCache);
14038 if(!(selector instanceof Array)){
14039 return rs[selector];
14041 for(var i = 0; i < selector.length; i++){
14042 if(rs[selector[i]]){
14043 return rs[selector[i]];
14051 * Updates a rule property
14052 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14053 * @param {String} property The css property
14054 * @param {String} value The new value for the property
14055 * @return {Boolean} true If a rule was found and updated
14057 updateRule : function(selector, property, value){
14058 if(!(selector instanceof Array)){
14059 var rule = this.getRule(selector);
14061 rule.style[property.replace(camelRe, camelFn)] = value;
14065 for(var i = 0; i < selector.length; i++){
14066 if(this.updateRule(selector[i], property, value)){
14076 * Ext JS Library 1.1.1
14077 * Copyright(c) 2006-2007, Ext JS, LLC.
14079 * Originally Released Under LGPL - original licence link has changed is not relivant.
14082 * <script type="text/javascript">
14088 * @class Roo.util.ClickRepeater
14089 * @extends Roo.util.Observable
14091 * A wrapper class which can be applied to any element. Fires a "click" event while the
14092 * mouse is pressed. The interval between firings may be specified in the config but
14093 * defaults to 10 milliseconds.
14095 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14097 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14098 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14099 * Similar to an autorepeat key delay.
14100 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14101 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14102 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14103 * "interval" and "delay" are ignored. "immediate" is honored.
14104 * @cfg {Boolean} preventDefault True to prevent the default click event
14105 * @cfg {Boolean} stopDefault True to stop the default click event
14108 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14109 * 2007-02-02 jvs Renamed to ClickRepeater
14110 * 2007-02-03 jvs Modifications for FF Mac and Safari
14113 * @param {String/HTMLElement/Element} el The element to listen on
14114 * @param {Object} config
14116 Roo.util.ClickRepeater = function(el, config)
14118 this.el = Roo.get(el);
14119 this.el.unselectable();
14121 Roo.apply(this, config);
14126 * Fires when the mouse button is depressed.
14127 * @param {Roo.util.ClickRepeater} this
14129 "mousedown" : true,
14132 * Fires on a specified interval during the time the element is pressed.
14133 * @param {Roo.util.ClickRepeater} this
14138 * Fires when the mouse key is released.
14139 * @param {Roo.util.ClickRepeater} this
14144 this.el.on("mousedown", this.handleMouseDown, this);
14145 if(this.preventDefault || this.stopDefault){
14146 this.el.on("click", function(e){
14147 if(this.preventDefault){
14148 e.preventDefault();
14150 if(this.stopDefault){
14156 // allow inline handler
14158 this.on("click", this.handler, this.scope || this);
14161 Roo.util.ClickRepeater.superclass.constructor.call(this);
14164 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14167 preventDefault : true,
14168 stopDefault : false,
14172 handleMouseDown : function(){
14173 clearTimeout(this.timer);
14175 if(this.pressClass){
14176 this.el.addClass(this.pressClass);
14178 this.mousedownTime = new Date();
14180 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14181 this.el.on("mouseout", this.handleMouseOut, this);
14183 this.fireEvent("mousedown", this);
14184 this.fireEvent("click", this);
14186 this.timer = this.click.defer(this.delay || this.interval, this);
14190 click : function(){
14191 this.fireEvent("click", this);
14192 this.timer = this.click.defer(this.getInterval(), this);
14196 getInterval: function(){
14197 if(!this.accelerate){
14198 return this.interval;
14200 var pressTime = this.mousedownTime.getElapsed();
14201 if(pressTime < 500){
14203 }else if(pressTime < 1700){
14205 }else if(pressTime < 2600){
14207 }else if(pressTime < 3500){
14209 }else if(pressTime < 4400){
14211 }else if(pressTime < 5300){
14213 }else if(pressTime < 6200){
14221 handleMouseOut : function(){
14222 clearTimeout(this.timer);
14223 if(this.pressClass){
14224 this.el.removeClass(this.pressClass);
14226 this.el.on("mouseover", this.handleMouseReturn, this);
14230 handleMouseReturn : function(){
14231 this.el.un("mouseover", this.handleMouseReturn);
14232 if(this.pressClass){
14233 this.el.addClass(this.pressClass);
14239 handleMouseUp : function(){
14240 clearTimeout(this.timer);
14241 this.el.un("mouseover", this.handleMouseReturn);
14242 this.el.un("mouseout", this.handleMouseOut);
14243 Roo.get(document).un("mouseup", this.handleMouseUp);
14244 this.el.removeClass(this.pressClass);
14245 this.fireEvent("mouseup", this);
14249 * Ext JS Library 1.1.1
14250 * Copyright(c) 2006-2007, Ext JS, LLC.
14252 * Originally Released Under LGPL - original licence link has changed is not relivant.
14255 * <script type="text/javascript">
14260 * @class Roo.KeyNav
14261 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14262 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14263 * way to implement custom navigation schemes for any UI component.</p>
14264 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14265 * pageUp, pageDown, del, home, end. Usage:</p>
14267 var nav = new Roo.KeyNav("my-element", {
14268 "left" : function(e){
14269 this.moveLeft(e.ctrlKey);
14271 "right" : function(e){
14272 this.moveRight(e.ctrlKey);
14274 "enter" : function(e){
14281 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14282 * @param {Object} config The config
14284 Roo.KeyNav = function(el, config){
14285 this.el = Roo.get(el);
14286 Roo.apply(this, config);
14287 if(!this.disabled){
14288 this.disabled = true;
14293 Roo.KeyNav.prototype = {
14295 * @cfg {Boolean} disabled
14296 * True to disable this KeyNav instance (defaults to false)
14300 * @cfg {String} defaultEventAction
14301 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14302 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14303 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14305 defaultEventAction: "stopEvent",
14307 * @cfg {Boolean} forceKeyDown
14308 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14309 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14310 * handle keydown instead of keypress.
14312 forceKeyDown : false,
14315 prepareEvent : function(e){
14316 var k = e.getKey();
14317 var h = this.keyToHandler[k];
14318 //if(h && this[h]){
14319 // e.stopPropagation();
14321 if(Roo.isSafari && h && k >= 37 && k <= 40){
14327 relay : function(e){
14328 var k = e.getKey();
14329 var h = this.keyToHandler[k];
14331 if(this.doRelay(e, this[h], h) !== true){
14332 e[this.defaultEventAction]();
14338 doRelay : function(e, h, hname){
14339 return h.call(this.scope || this, e);
14342 // possible handlers
14356 // quick lookup hash
14373 * Enable this KeyNav
14375 enable: function(){
14377 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14378 // the EventObject will normalize Safari automatically
14379 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14380 this.el.on("keydown", this.relay, this);
14382 this.el.on("keydown", this.prepareEvent, this);
14383 this.el.on("keypress", this.relay, this);
14385 this.disabled = false;
14390 * Disable this KeyNav
14392 disable: function(){
14393 if(!this.disabled){
14394 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14395 this.el.un("keydown", this.relay);
14397 this.el.un("keydown", this.prepareEvent);
14398 this.el.un("keypress", this.relay);
14400 this.disabled = true;
14405 * Ext JS Library 1.1.1
14406 * Copyright(c) 2006-2007, Ext JS, LLC.
14408 * Originally Released Under LGPL - original licence link has changed is not relivant.
14411 * <script type="text/javascript">
14416 * @class Roo.KeyMap
14417 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14418 * The constructor accepts the same config object as defined by {@link #addBinding}.
14419 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14420 * combination it will call the function with this signature (if the match is a multi-key
14421 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14422 * A KeyMap can also handle a string representation of keys.<br />
14425 // map one key by key code
14426 var map = new Roo.KeyMap("my-element", {
14427 key: 13, // or Roo.EventObject.ENTER
14432 // map multiple keys to one action by string
14433 var map = new Roo.KeyMap("my-element", {
14439 // map multiple keys to multiple actions by strings and array of codes
14440 var map = new Roo.KeyMap("my-element", [
14443 fn: function(){ alert("Return was pressed"); }
14446 fn: function(){ alert('a, b or c was pressed'); }
14451 fn: function(){ alert('Control + shift + tab was pressed.'); }
14455 * <b>Note: A KeyMap starts enabled</b>
14457 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14458 * @param {Object} config The config (see {@link #addBinding})
14459 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14461 Roo.KeyMap = function(el, config, eventName){
14462 this.el = Roo.get(el);
14463 this.eventName = eventName || "keydown";
14464 this.bindings = [];
14466 this.addBinding(config);
14471 Roo.KeyMap.prototype = {
14473 * True to stop the event from bubbling and prevent the default browser action if the
14474 * key was handled by the KeyMap (defaults to false)
14480 * Add a new binding to this KeyMap. The following config object properties are supported:
14482 Property Type Description
14483 ---------- --------------- ----------------------------------------------------------------------
14484 key String/Array A single keycode or an array of keycodes to handle
14485 shift Boolean True to handle key only when shift is pressed (defaults to false)
14486 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14487 alt Boolean True to handle key only when alt is pressed (defaults to false)
14488 fn Function The function to call when KeyMap finds the expected key combination
14489 scope Object The scope of the callback function
14495 var map = new Roo.KeyMap(document, {
14496 key: Roo.EventObject.ENTER,
14501 //Add a new binding to the existing KeyMap later
14509 * @param {Object/Array} config A single KeyMap config or an array of configs
14511 addBinding : function(config){
14512 if(config instanceof Array){
14513 for(var i = 0, len = config.length; i < len; i++){
14514 this.addBinding(config[i]);
14518 var keyCode = config.key,
14519 shift = config.shift,
14520 ctrl = config.ctrl,
14523 scope = config.scope;
14524 if(typeof keyCode == "string"){
14526 var keyString = keyCode.toUpperCase();
14527 for(var j = 0, len = keyString.length; j < len; j++){
14528 ks.push(keyString.charCodeAt(j));
14532 var keyArray = keyCode instanceof Array;
14533 var handler = function(e){
14534 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14535 var k = e.getKey();
14537 for(var i = 0, len = keyCode.length; i < len; i++){
14538 if(keyCode[i] == k){
14539 if(this.stopEvent){
14542 fn.call(scope || window, k, e);
14548 if(this.stopEvent){
14551 fn.call(scope || window, k, e);
14556 this.bindings.push(handler);
14560 * Shorthand for adding a single key listener
14561 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14562 * following options:
14563 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14564 * @param {Function} fn The function to call
14565 * @param {Object} scope (optional) The scope of the function
14567 on : function(key, fn, scope){
14568 var keyCode, shift, ctrl, alt;
14569 if(typeof key == "object" && !(key instanceof Array)){
14588 handleKeyDown : function(e){
14589 if(this.enabled){ //just in case
14590 var b = this.bindings;
14591 for(var i = 0, len = b.length; i < len; i++){
14592 b[i].call(this, e);
14598 * Returns true if this KeyMap is enabled
14599 * @return {Boolean}
14601 isEnabled : function(){
14602 return this.enabled;
14606 * Enables this KeyMap
14608 enable: function(){
14610 this.el.on(this.eventName, this.handleKeyDown, this);
14611 this.enabled = true;
14616 * Disable this KeyMap
14618 disable: function(){
14620 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14621 this.enabled = false;
14626 * Ext JS Library 1.1.1
14627 * Copyright(c) 2006-2007, Ext JS, LLC.
14629 * Originally Released Under LGPL - original licence link has changed is not relivant.
14632 * <script type="text/javascript">
14637 * @class Roo.util.TextMetrics
14638 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14639 * wide, in pixels, a given block of text will be.
14642 Roo.util.TextMetrics = function(){
14646 * Measures the size of the specified text
14647 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14648 * that can affect the size of the rendered text
14649 * @param {String} text The text to measure
14650 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14651 * in order to accurately measure the text height
14652 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14654 measure : function(el, text, fixedWidth){
14656 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14659 shared.setFixedWidth(fixedWidth || 'auto');
14660 return shared.getSize(text);
14664 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14665 * the overhead of multiple calls to initialize the style properties on each measurement.
14666 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14667 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14668 * in order to accurately measure the text height
14669 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14671 createInstance : function(el, fixedWidth){
14672 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14679 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14680 var ml = new Roo.Element(document.createElement('div'));
14681 document.body.appendChild(ml.dom);
14682 ml.position('absolute');
14683 ml.setLeftTop(-1000, -1000);
14687 ml.setWidth(fixedWidth);
14692 * Returns the size of the specified text based on the internal element's style and width properties
14693 * @memberOf Roo.util.TextMetrics.Instance#
14694 * @param {String} text The text to measure
14695 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14697 getSize : function(text){
14699 var s = ml.getSize();
14705 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14706 * that can affect the size of the rendered text
14707 * @memberOf Roo.util.TextMetrics.Instance#
14708 * @param {String/HTMLElement} el The element, dom node or id
14710 bind : function(el){
14712 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14717 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14718 * to set a fixed width in order to accurately measure the text height.
14719 * @memberOf Roo.util.TextMetrics.Instance#
14720 * @param {Number} width The width to set on the element
14722 setFixedWidth : function(width){
14723 ml.setWidth(width);
14727 * Returns the measured width of the specified text
14728 * @memberOf Roo.util.TextMetrics.Instance#
14729 * @param {String} text The text to measure
14730 * @return {Number} width The width in pixels
14732 getWidth : function(text){
14733 ml.dom.style.width = 'auto';
14734 return this.getSize(text).width;
14738 * Returns the measured height of the specified text. For multiline text, be sure to call
14739 * {@link #setFixedWidth} if necessary.
14740 * @memberOf Roo.util.TextMetrics.Instance#
14741 * @param {String} text The text to measure
14742 * @return {Number} height The height in pixels
14744 getHeight : function(text){
14745 return this.getSize(text).height;
14749 instance.bind(bindTo);
14754 // backwards compat
14755 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14757 * Ext JS Library 1.1.1
14758 * Copyright(c) 2006-2007, Ext JS, LLC.
14760 * Originally Released Under LGPL - original licence link has changed is not relivant.
14763 * <script type="text/javascript">
14767 * @class Roo.state.Provider
14768 * Abstract base class for state provider implementations. This class provides methods
14769 * for encoding and decoding <b>typed</b> variables including dates and defines the
14770 * Provider interface.
14772 Roo.state.Provider = function(){
14774 * @event statechange
14775 * Fires when a state change occurs.
14776 * @param {Provider} this This state provider
14777 * @param {String} key The state key which was changed
14778 * @param {String} value The encoded value for the state
14781 "statechange": true
14784 Roo.state.Provider.superclass.constructor.call(this);
14786 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14788 * Returns the current value for a key
14789 * @param {String} name The key name
14790 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14791 * @return {Mixed} The state data
14793 get : function(name, defaultValue){
14794 return typeof this.state[name] == "undefined" ?
14795 defaultValue : this.state[name];
14799 * Clears a value from the state
14800 * @param {String} name The key name
14802 clear : function(name){
14803 delete this.state[name];
14804 this.fireEvent("statechange", this, name, null);
14808 * Sets the value for a key
14809 * @param {String} name The key name
14810 * @param {Mixed} value The value to set
14812 set : function(name, value){
14813 this.state[name] = value;
14814 this.fireEvent("statechange", this, name, value);
14818 * Decodes a string previously encoded with {@link #encodeValue}.
14819 * @param {String} value The value to decode
14820 * @return {Mixed} The decoded value
14822 decodeValue : function(cookie){
14823 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14824 var matches = re.exec(unescape(cookie));
14825 if(!matches || !matches[1]) {
14826 return; // non state cookie
14828 var type = matches[1];
14829 var v = matches[2];
14832 return parseFloat(v);
14834 return new Date(Date.parse(v));
14839 var values = v.split("^");
14840 for(var i = 0, len = values.length; i < len; i++){
14841 all.push(this.decodeValue(values[i]));
14846 var values = v.split("^");
14847 for(var i = 0, len = values.length; i < len; i++){
14848 var kv = values[i].split("=");
14849 all[kv[0]] = this.decodeValue(kv[1]);
14858 * Encodes a value including type information. Decode with {@link #decodeValue}.
14859 * @param {Mixed} value The value to encode
14860 * @return {String} The encoded value
14862 encodeValue : function(v){
14864 if(typeof v == "number"){
14866 }else if(typeof v == "boolean"){
14867 enc = "b:" + (v ? "1" : "0");
14868 }else if(v instanceof Date){
14869 enc = "d:" + v.toGMTString();
14870 }else if(v instanceof Array){
14872 for(var i = 0, len = v.length; i < len; i++){
14873 flat += this.encodeValue(v[i]);
14879 }else if(typeof v == "object"){
14882 if(typeof v[key] != "function"){
14883 flat += key + "=" + this.encodeValue(v[key]) + "^";
14886 enc = "o:" + flat.substring(0, flat.length-1);
14890 return escape(enc);
14896 * Ext JS Library 1.1.1
14897 * Copyright(c) 2006-2007, Ext JS, LLC.
14899 * Originally Released Under LGPL - original licence link has changed is not relivant.
14902 * <script type="text/javascript">
14905 * @class Roo.state.Manager
14906 * This is the global state manager. By default all components that are "state aware" check this class
14907 * for state information if you don't pass them a custom state provider. In order for this class
14908 * to be useful, it must be initialized with a provider when your application initializes.
14910 // in your initialization function
14912 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14914 // supposed you have a {@link Roo.BorderLayout}
14915 var layout = new Roo.BorderLayout(...);
14916 layout.restoreState();
14917 // or a {Roo.BasicDialog}
14918 var dialog = new Roo.BasicDialog(...);
14919 dialog.restoreState();
14923 Roo.state.Manager = function(){
14924 var provider = new Roo.state.Provider();
14928 * Configures the default state provider for your application
14929 * @param {Provider} stateProvider The state provider to set
14931 setProvider : function(stateProvider){
14932 provider = stateProvider;
14936 * Returns the current value for a key
14937 * @param {String} name The key name
14938 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14939 * @return {Mixed} The state data
14941 get : function(key, defaultValue){
14942 return provider.get(key, defaultValue);
14946 * Sets the value for a key
14947 * @param {String} name The key name
14948 * @param {Mixed} value The state data
14950 set : function(key, value){
14951 provider.set(key, value);
14955 * Clears a value from the state
14956 * @param {String} name The key name
14958 clear : function(key){
14959 provider.clear(key);
14963 * Gets the currently configured state provider
14964 * @return {Provider} The state provider
14966 getProvider : function(){
14973 * Ext JS Library 1.1.1
14974 * Copyright(c) 2006-2007, Ext JS, LLC.
14976 * Originally Released Under LGPL - original licence link has changed is not relivant.
14979 * <script type="text/javascript">
14982 * @class Roo.state.CookieProvider
14983 * @extends Roo.state.Provider
14984 * The default Provider implementation which saves state via cookies.
14987 var cp = new Roo.state.CookieProvider({
14989 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14990 domain: "roojs.com"
14992 Roo.state.Manager.setProvider(cp);
14994 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14995 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14996 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14997 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14998 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14999 * domain the page is running on including the 'www' like 'www.roojs.com')
15000 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15002 * Create a new CookieProvider
15003 * @param {Object} config The configuration object
15005 Roo.state.CookieProvider = function(config){
15006 Roo.state.CookieProvider.superclass.constructor.call(this);
15008 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15009 this.domain = null;
15010 this.secure = false;
15011 Roo.apply(this, config);
15012 this.state = this.readCookies();
15015 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15017 set : function(name, value){
15018 if(typeof value == "undefined" || value === null){
15022 this.setCookie(name, value);
15023 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15027 clear : function(name){
15028 this.clearCookie(name);
15029 Roo.state.CookieProvider.superclass.clear.call(this, name);
15033 readCookies : function(){
15035 var c = document.cookie + ";";
15036 var re = /\s?(.*?)=(.*?);/g;
15038 while((matches = re.exec(c)) != null){
15039 var name = matches[1];
15040 var value = matches[2];
15041 if(name && name.substring(0,3) == "ys-"){
15042 cookies[name.substr(3)] = this.decodeValue(value);
15049 setCookie : function(name, value){
15050 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15051 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15052 ((this.path == null) ? "" : ("; path=" + this.path)) +
15053 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15054 ((this.secure == true) ? "; secure" : "");
15058 clearCookie : function(name){
15059 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15060 ((this.path == null) ? "" : ("; path=" + this.path)) +
15061 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15062 ((this.secure == true) ? "; secure" : "");
15066 * Ext JS Library 1.1.1
15067 * Copyright(c) 2006-2007, Ext JS, LLC.
15069 * Originally Released Under LGPL - original licence link has changed is not relivant.
15072 * <script type="text/javascript">
15077 * @class Roo.ComponentMgr
15078 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15081 Roo.ComponentMgr = function(){
15082 var all = new Roo.util.MixedCollection();
15086 * Registers a component.
15087 * @param {Roo.Component} c The component
15089 register : function(c){
15094 * Unregisters a component.
15095 * @param {Roo.Component} c The component
15097 unregister : function(c){
15102 * Returns a component by id
15103 * @param {String} id The component id
15105 get : function(id){
15106 return all.get(id);
15110 * Registers a function that will be called when a specified component is added to ComponentMgr
15111 * @param {String} id The component id
15112 * @param {Funtction} fn The callback function
15113 * @param {Object} scope The scope of the callback
15115 onAvailable : function(id, fn, scope){
15116 all.on("add", function(index, o){
15118 fn.call(scope || o, o);
15119 all.un("add", fn, scope);
15126 * Ext JS Library 1.1.1
15127 * Copyright(c) 2006-2007, Ext JS, LLC.
15129 * Originally Released Under LGPL - original licence link has changed is not relivant.
15132 * <script type="text/javascript">
15136 * @class Roo.Component
15137 * @extends Roo.util.Observable
15138 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15139 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15140 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15141 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15142 * All visual components (widgets) that require rendering into a layout should subclass Component.
15144 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15145 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15146 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15148 Roo.Component = function(config){
15149 config = config || {};
15150 if(config.tagName || config.dom || typeof config == "string"){ // element object
15151 config = {el: config, id: config.id || config};
15153 this.initialConfig = config;
15155 Roo.apply(this, config);
15159 * Fires after the component is disabled.
15160 * @param {Roo.Component} this
15165 * Fires after the component is enabled.
15166 * @param {Roo.Component} this
15170 * @event beforeshow
15171 * Fires before the component is shown. Return false to stop the show.
15172 * @param {Roo.Component} this
15177 * Fires after the component is shown.
15178 * @param {Roo.Component} this
15182 * @event beforehide
15183 * Fires before the component is hidden. Return false to stop the hide.
15184 * @param {Roo.Component} this
15189 * Fires after the component is hidden.
15190 * @param {Roo.Component} this
15194 * @event beforerender
15195 * Fires before the component is rendered. Return false to stop the render.
15196 * @param {Roo.Component} this
15198 beforerender : true,
15201 * Fires after the component is rendered.
15202 * @param {Roo.Component} this
15206 * @event beforedestroy
15207 * Fires before the component is destroyed. Return false to stop the destroy.
15208 * @param {Roo.Component} this
15210 beforedestroy : true,
15213 * Fires after the component is destroyed.
15214 * @param {Roo.Component} this
15219 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15221 Roo.ComponentMgr.register(this);
15222 Roo.Component.superclass.constructor.call(this);
15223 this.initComponent();
15224 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15225 this.render(this.renderTo);
15226 delete this.renderTo;
15231 Roo.Component.AUTO_ID = 1000;
15233 Roo.extend(Roo.Component, Roo.util.Observable, {
15235 * @scope Roo.Component.prototype
15237 * true if this component is hidden. Read-only.
15242 * true if this component is disabled. Read-only.
15247 * true if this component has been rendered. Read-only.
15251 /** @cfg {String} disableClass
15252 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15254 disabledClass : "x-item-disabled",
15255 /** @cfg {Boolean} allowDomMove
15256 * Whether the component can move the Dom node when rendering (defaults to true).
15258 allowDomMove : true,
15259 /** @cfg {String} hideMode (display|visibility)
15260 * How this component should hidden. Supported values are
15261 * "visibility" (css visibility), "offsets" (negative offset position) and
15262 * "display" (css display) - defaults to "display".
15264 hideMode: 'display',
15267 ctype : "Roo.Component",
15270 * @cfg {String} actionMode
15271 * which property holds the element that used for hide() / show() / disable() / enable()
15277 getActionEl : function(){
15278 return this[this.actionMode];
15281 initComponent : Roo.emptyFn,
15283 * If this is a lazy rendering component, render it to its container element.
15284 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15286 render : function(container, position){
15287 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15288 if(!container && this.el){
15289 this.el = Roo.get(this.el);
15290 container = this.el.dom.parentNode;
15291 this.allowDomMove = false;
15293 this.container = Roo.get(container);
15294 this.rendered = true;
15295 if(position !== undefined){
15296 if(typeof position == 'number'){
15297 position = this.container.dom.childNodes[position];
15299 position = Roo.getDom(position);
15302 this.onRender(this.container, position || null);
15304 this.el.addClass(this.cls);
15308 this.el.applyStyles(this.style);
15311 this.fireEvent("render", this);
15312 this.afterRender(this.container);
15324 // default function is not really useful
15325 onRender : function(ct, position){
15327 this.el = Roo.get(this.el);
15328 if(this.allowDomMove !== false){
15329 ct.dom.insertBefore(this.el.dom, position);
15335 getAutoCreate : function(){
15336 var cfg = typeof this.autoCreate == "object" ?
15337 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15338 if(this.id && !cfg.id){
15345 afterRender : Roo.emptyFn,
15348 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15349 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15351 destroy : function(){
15352 if(this.fireEvent("beforedestroy", this) !== false){
15353 this.purgeListeners();
15354 this.beforeDestroy();
15356 this.el.removeAllListeners();
15358 if(this.actionMode == "container"){
15359 this.container.remove();
15363 Roo.ComponentMgr.unregister(this);
15364 this.fireEvent("destroy", this);
15369 beforeDestroy : function(){
15374 onDestroy : function(){
15379 * Returns the underlying {@link Roo.Element}.
15380 * @return {Roo.Element} The element
15382 getEl : function(){
15387 * Returns the id of this component.
15390 getId : function(){
15395 * Try to focus this component.
15396 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15397 * @return {Roo.Component} this
15399 focus : function(selectText){
15402 if(selectText === true){
15403 this.el.dom.select();
15418 * Disable this component.
15419 * @return {Roo.Component} this
15421 disable : function(){
15425 this.disabled = true;
15426 this.fireEvent("disable", this);
15431 onDisable : function(){
15432 this.getActionEl().addClass(this.disabledClass);
15433 this.el.dom.disabled = true;
15437 * Enable this component.
15438 * @return {Roo.Component} this
15440 enable : function(){
15444 this.disabled = false;
15445 this.fireEvent("enable", this);
15450 onEnable : function(){
15451 this.getActionEl().removeClass(this.disabledClass);
15452 this.el.dom.disabled = false;
15456 * Convenience function for setting disabled/enabled by boolean.
15457 * @param {Boolean} disabled
15459 setDisabled : function(disabled){
15460 this[disabled ? "disable" : "enable"]();
15464 * Show this component.
15465 * @return {Roo.Component} this
15468 if(this.fireEvent("beforeshow", this) !== false){
15469 this.hidden = false;
15473 this.fireEvent("show", this);
15479 onShow : function(){
15480 var ae = this.getActionEl();
15481 if(this.hideMode == 'visibility'){
15482 ae.dom.style.visibility = "visible";
15483 }else if(this.hideMode == 'offsets'){
15484 ae.removeClass('x-hidden');
15486 ae.dom.style.display = "";
15491 * Hide this component.
15492 * @return {Roo.Component} this
15495 if(this.fireEvent("beforehide", this) !== false){
15496 this.hidden = true;
15500 this.fireEvent("hide", this);
15506 onHide : function(){
15507 var ae = this.getActionEl();
15508 if(this.hideMode == 'visibility'){
15509 ae.dom.style.visibility = "hidden";
15510 }else if(this.hideMode == 'offsets'){
15511 ae.addClass('x-hidden');
15513 ae.dom.style.display = "none";
15518 * Convenience function to hide or show this component by boolean.
15519 * @param {Boolean} visible True to show, false to hide
15520 * @return {Roo.Component} this
15522 setVisible: function(visible){
15532 * Returns true if this component is visible.
15534 isVisible : function(){
15535 return this.getActionEl().isVisible();
15538 cloneConfig : function(overrides){
15539 overrides = overrides || {};
15540 var id = overrides.id || Roo.id();
15541 var cfg = Roo.applyIf(overrides, this.initialConfig);
15542 cfg.id = id; // prevent dup id
15543 return new this.constructor(cfg);
15547 * Ext JS Library 1.1.1
15548 * Copyright(c) 2006-2007, Ext JS, LLC.
15550 * Originally Released Under LGPL - original licence link has changed is not relivant.
15553 * <script type="text/javascript">
15557 * @class Roo.BoxComponent
15558 * @extends Roo.Component
15559 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15560 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15561 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15562 * layout containers.
15564 * @param {Roo.Element/String/Object} config The configuration options.
15566 Roo.BoxComponent = function(config){
15567 Roo.Component.call(this, config);
15571 * Fires after the component is resized.
15572 * @param {Roo.Component} this
15573 * @param {Number} adjWidth The box-adjusted width that was set
15574 * @param {Number} adjHeight The box-adjusted height that was set
15575 * @param {Number} rawWidth The width that was originally specified
15576 * @param {Number} rawHeight The height that was originally specified
15581 * Fires after the component is moved.
15582 * @param {Roo.Component} this
15583 * @param {Number} x The new x position
15584 * @param {Number} y The new y position
15590 Roo.extend(Roo.BoxComponent, Roo.Component, {
15591 // private, set in afterRender to signify that the component has been rendered
15593 // private, used to defer height settings to subclasses
15594 deferHeight: false,
15595 /** @cfg {Number} width
15596 * width (optional) size of component
15598 /** @cfg {Number} height
15599 * height (optional) size of component
15603 * Sets the width and height of the component. This method fires the resize event. This method can accept
15604 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15605 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15606 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15607 * @return {Roo.BoxComponent} this
15609 setSize : function(w, h){
15610 // support for standard size objects
15611 if(typeof w == 'object'){
15616 if(!this.boxReady){
15622 // prevent recalcs when not needed
15623 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15626 this.lastSize = {width: w, height: h};
15628 var adj = this.adjustSize(w, h);
15629 var aw = adj.width, ah = adj.height;
15630 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15631 var rz = this.getResizeEl();
15632 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15633 rz.setSize(aw, ah);
15634 }else if(!this.deferHeight && ah !== undefined){
15636 }else if(aw !== undefined){
15639 this.onResize(aw, ah, w, h);
15640 this.fireEvent('resize', this, aw, ah, w, h);
15646 * Gets the current size of the component's underlying element.
15647 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15649 getSize : function(){
15650 return this.el.getSize();
15654 * Gets the current XY position of the component's underlying element.
15655 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15656 * @return {Array} The XY position of the element (e.g., [100, 200])
15658 getPosition : function(local){
15659 if(local === true){
15660 return [this.el.getLeft(true), this.el.getTop(true)];
15662 return this.xy || this.el.getXY();
15666 * Gets the current box measurements of the component's underlying element.
15667 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15668 * @returns {Object} box An object in the format {x, y, width, height}
15670 getBox : function(local){
15671 var s = this.el.getSize();
15673 s.x = this.el.getLeft(true);
15674 s.y = this.el.getTop(true);
15676 var xy = this.xy || this.el.getXY();
15684 * Sets the current box measurements of the component's underlying element.
15685 * @param {Object} box An object in the format {x, y, width, height}
15686 * @returns {Roo.BoxComponent} this
15688 updateBox : function(box){
15689 this.setSize(box.width, box.height);
15690 this.setPagePosition(box.x, box.y);
15695 getResizeEl : function(){
15696 return this.resizeEl || this.el;
15700 getPositionEl : function(){
15701 return this.positionEl || this.el;
15705 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15706 * This method fires the move event.
15707 * @param {Number} left The new left
15708 * @param {Number} top The new top
15709 * @returns {Roo.BoxComponent} this
15711 setPosition : function(x, y){
15714 if(!this.boxReady){
15717 var adj = this.adjustPosition(x, y);
15718 var ax = adj.x, ay = adj.y;
15720 var el = this.getPositionEl();
15721 if(ax !== undefined || ay !== undefined){
15722 if(ax !== undefined && ay !== undefined){
15723 el.setLeftTop(ax, ay);
15724 }else if(ax !== undefined){
15726 }else if(ay !== undefined){
15729 this.onPosition(ax, ay);
15730 this.fireEvent('move', this, ax, ay);
15736 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15737 * This method fires the move event.
15738 * @param {Number} x The new x position
15739 * @param {Number} y The new y position
15740 * @returns {Roo.BoxComponent} this
15742 setPagePosition : function(x, y){
15745 if(!this.boxReady){
15748 if(x === undefined || y === undefined){ // cannot translate undefined points
15751 var p = this.el.translatePoints(x, y);
15752 this.setPosition(p.left, p.top);
15757 onRender : function(ct, position){
15758 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15760 this.resizeEl = Roo.get(this.resizeEl);
15762 if(this.positionEl){
15763 this.positionEl = Roo.get(this.positionEl);
15768 afterRender : function(){
15769 Roo.BoxComponent.superclass.afterRender.call(this);
15770 this.boxReady = true;
15771 this.setSize(this.width, this.height);
15772 if(this.x || this.y){
15773 this.setPosition(this.x, this.y);
15775 if(this.pageX || this.pageY){
15776 this.setPagePosition(this.pageX, this.pageY);
15781 * Force the component's size to recalculate based on the underlying element's current height and width.
15782 * @returns {Roo.BoxComponent} this
15784 syncSize : function(){
15785 delete this.lastSize;
15786 this.setSize(this.el.getWidth(), this.el.getHeight());
15791 * Called after the component is resized, this method is empty by default but can be implemented by any
15792 * subclass that needs to perform custom logic after a resize occurs.
15793 * @param {Number} adjWidth The box-adjusted width that was set
15794 * @param {Number} adjHeight The box-adjusted height that was set
15795 * @param {Number} rawWidth The width that was originally specified
15796 * @param {Number} rawHeight The height that was originally specified
15798 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15803 * Called after the component is moved, this method is empty by default but can be implemented by any
15804 * subclass that needs to perform custom logic after a move occurs.
15805 * @param {Number} x The new x position
15806 * @param {Number} y The new y position
15808 onPosition : function(x, y){
15813 adjustSize : function(w, h){
15814 if(this.autoWidth){
15817 if(this.autoHeight){
15820 return {width : w, height: h};
15824 adjustPosition : function(x, y){
15825 return {x : x, y: y};
15828 * Original code for Roojs - LGPL
15829 * <script type="text/javascript">
15833 * @class Roo.XComponent
15834 * A delayed Element creator...
15835 * Or a way to group chunks of interface together.
15836 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15837 * used in conjunction with XComponent.build() it will create an instance of each element,
15838 * then call addxtype() to build the User interface.
15840 * Mypart.xyx = new Roo.XComponent({
15842 parent : 'Mypart.xyz', // empty == document.element.!!
15846 disabled : function() {}
15848 tree : function() { // return an tree of xtype declared components
15852 xtype : 'NestedLayoutPanel',
15859 * It can be used to build a big heiracy, with parent etc.
15860 * or you can just use this to render a single compoent to a dom element
15861 * MYPART.render(Roo.Element | String(id) | dom_element )
15868 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15869 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15871 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15873 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15874 * - if mulitple topModules exist, the last one is defined as the top module.
15878 * When the top level or multiple modules are to embedded into a existing HTML page,
15879 * the parent element can container '#id' of the element where the module will be drawn.
15883 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15884 * it relies more on a include mechanism, where sub modules are included into an outer page.
15885 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15887 * Bootstrap Roo Included elements
15889 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15890 * hence confusing the component builder as it thinks there are multiple top level elements.
15894 * @extends Roo.util.Observable
15896 * @param cfg {Object} configuration of component
15899 Roo.XComponent = function(cfg) {
15900 Roo.apply(this, cfg);
15904 * Fires when this the componnt is built
15905 * @param {Roo.XComponent} c the component
15910 this.region = this.region || 'center'; // default..
15911 Roo.XComponent.register(this);
15912 this.modules = false;
15913 this.el = false; // where the layout goes..
15917 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15920 * The created element (with Roo.factory())
15921 * @type {Roo.Layout}
15927 * for BC - use el in new code
15928 * @type {Roo.Layout}
15934 * for BC - use el in new code
15935 * @type {Roo.Layout}
15940 * @cfg {Function|boolean} disabled
15941 * If this module is disabled by some rule, return true from the funtion
15946 * @cfg {String} parent
15947 * Name of parent element which it get xtype added to..
15952 * @cfg {String} order
15953 * Used to set the order in which elements are created (usefull for multiple tabs)
15958 * @cfg {String} name
15959 * String to display while loading.
15963 * @cfg {String} region
15964 * Region to render component to (defaults to center)
15969 * @cfg {Array} items
15970 * A single item array - the first element is the root of the tree..
15971 * It's done this way to stay compatible with the Xtype system...
15977 * The method that retuns the tree of parts that make up this compoennt
15984 * render element to dom or tree
15985 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15988 render : function(el)
15992 var hp = this.parent ? 1 : 0;
15993 Roo.debug && Roo.log(this);
15995 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15996 // if parent is a '#.....' string, then let's use that..
15997 var ename = this.parent.substr(1);
15998 this.parent = false;
15999 Roo.debug && Roo.log(ename);
16001 case 'bootstrap-body' :
16002 if (typeof(Roo.bootstrap.Body) != 'undefined') {
16003 this.parent = { el : new Roo.bootstrap.Body() };
16004 Roo.debug && Roo.log("setting el to doc body");
16007 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16011 this.parent = { el : true};
16014 el = Roo.get(ename);
16019 if (!el && !this.parent) {
16020 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16024 Roo.debug && Roo.log("EL:");
16025 Roo.debug && Roo.log(el);
16026 Roo.debug && Roo.log("this.parent.el:");
16027 Roo.debug && Roo.log(this.parent.el);
16029 var tree = this._tree ? this._tree() : this.tree();
16031 // altertive root elements ??? - we need a better way to indicate these.
16032 var is_alt = Roo.XComponent.is_alt || (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16033 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16035 if (!this.parent && is_alt) {
16036 //el = Roo.get(document.body);
16037 this.parent = { el : true };
16042 if (!this.parent) {
16044 Roo.debug && Roo.log("no parent - creating one");
16046 el = el ? Roo.get(el) : false;
16048 // it's a top level one..
16050 el : new Roo.BorderLayout(el || document.body, {
16056 tabPosition: 'top',
16057 //resizeTabs: true,
16058 alwaysShowTabs: el && hp? false : true,
16059 hideTabs: el || !hp ? true : false,
16066 if (!this.parent.el) {
16067 // probably an old style ctor, which has been disabled.
16071 // The 'tree' method is '_tree now'
16073 tree.region = tree.region || this.region;
16074 var is_body = false;
16075 if (this.parent.el === true) {
16076 // bootstrap... - body..
16077 this.parent.el = Roo.factory(tree);
16081 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16082 this.fireEvent('built', this);
16084 this.panel = this.el;
16085 this.layout = this.panel.layout;
16086 this.parentLayout = this.parent.layout || false;
16092 Roo.apply(Roo.XComponent, {
16094 * @property hideProgress
16095 * true to disable the building progress bar.. usefull on single page renders.
16098 hideProgress : false,
16100 * @property buildCompleted
16101 * True when the builder has completed building the interface.
16104 buildCompleted : false,
16107 * @property topModule
16108 * the upper most module - uses document.element as it's constructor.
16115 * @property modules
16116 * array of modules to be created by registration system.
16117 * @type {Array} of Roo.XComponent
16122 * @property elmodules
16123 * array of modules to be created by which use #ID
16124 * @type {Array} of Roo.XComponent
16131 * Is an alternative Root - normally used by bootstrap or other systems,
16132 * where the top element in the tree can wrap 'body'
16133 * @type {boolean} (default false)
16138 * @property build_from_html
16139 * Build elements from html - used by bootstrap HTML stuff
16140 * - this is cleared after build is completed
16141 * @type {boolean} (default false)
16144 build_from_html : false,
16146 * Register components to be built later.
16148 * This solves the following issues
16149 * - Building is not done on page load, but after an authentication process has occured.
16150 * - Interface elements are registered on page load
16151 * - Parent Interface elements may not be loaded before child, so this handles that..
16158 module : 'Pman.Tab.projectMgr',
16160 parent : 'Pman.layout',
16161 disabled : false, // or use a function..
16164 * * @param {Object} details about module
16166 register : function(obj) {
16168 Roo.XComponent.event.fireEvent('register', obj);
16169 switch(typeof(obj.disabled) ) {
16175 if ( obj.disabled() ) {
16181 if (obj.disabled) {
16187 this.modules.push(obj);
16191 * convert a string to an object..
16192 * eg. 'AAA.BBB' -> finds AAA.BBB
16196 toObject : function(str)
16198 if (!str || typeof(str) == 'object') {
16201 if (str.substring(0,1) == '#') {
16205 var ar = str.split('.');
16210 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16212 throw "Module not found : " + str;
16216 throw "Module not found : " + str;
16218 Roo.each(ar, function(e) {
16219 if (typeof(o[e]) == 'undefined') {
16220 throw "Module not found : " + str;
16231 * move modules into their correct place in the tree..
16234 preBuild : function ()
16237 Roo.each(this.modules , function (obj)
16239 Roo.XComponent.event.fireEvent('beforebuild', obj);
16241 var opar = obj.parent;
16243 obj.parent = this.toObject(opar);
16245 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16250 Roo.debug && Roo.log("GOT top level module");
16251 Roo.debug && Roo.log(obj);
16252 obj.modules = new Roo.util.MixedCollection(false,
16253 function(o) { return o.order + '' }
16255 this.topModule = obj;
16258 // parent is a string (usually a dom element name..)
16259 if (typeof(obj.parent) == 'string') {
16260 this.elmodules.push(obj);
16263 if (obj.parent.constructor != Roo.XComponent) {
16264 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16266 if (!obj.parent.modules) {
16267 obj.parent.modules = new Roo.util.MixedCollection(false,
16268 function(o) { return o.order + '' }
16271 if (obj.parent.disabled) {
16272 obj.disabled = true;
16274 obj.parent.modules.add(obj);
16279 * make a list of modules to build.
16280 * @return {Array} list of modules.
16283 buildOrder : function()
16286 var cmp = function(a,b) {
16287 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16289 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16290 throw "No top level modules to build";
16293 // make a flat list in order of modules to build.
16294 var mods = this.topModule ? [ this.topModule ] : [];
16297 // elmodules (is a list of DOM based modules )
16298 Roo.each(this.elmodules, function(e) {
16300 if (!this.topModule &&
16301 typeof(e.parent) == 'string' &&
16302 e.parent.substring(0,1) == '#' &&
16303 Roo.get(e.parent.substr(1))
16306 _this.topModule = e;
16312 // add modules to their parents..
16313 var addMod = function(m) {
16314 Roo.debug && Roo.log("build Order: add: " + m.name);
16317 if (m.modules && !m.disabled) {
16318 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16319 m.modules.keySort('ASC', cmp );
16320 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16322 m.modules.each(addMod);
16324 Roo.debug && Roo.log("build Order: no child modules");
16326 // not sure if this is used any more..
16328 m.finalize.name = m.name + " (clean up) ";
16329 mods.push(m.finalize);
16333 if (this.topModule && this.topModule.modules) {
16334 this.topModule.modules.keySort('ASC', cmp );
16335 this.topModule.modules.each(addMod);
16341 * Build the registered modules.
16342 * @param {Object} parent element.
16343 * @param {Function} optional method to call after module has been added.
16347 build : function(opts)
16350 if (typeof(opts) != 'undefined') {
16351 Roo.apply(this,opts);
16355 var mods = this.buildOrder();
16357 //this.allmods = mods;
16358 //Roo.debug && Roo.log(mods);
16360 if (!mods.length) { // should not happen
16361 throw "NO modules!!!";
16365 var msg = "Building Interface...";
16366 // flash it up as modal - so we store the mask!?
16367 if (!this.hideProgress && Roo.MessageBox) {
16368 Roo.MessageBox.show({ title: 'loading' });
16369 Roo.MessageBox.show({
16370 title: "Please wait...",
16379 var total = mods.length;
16382 var progressRun = function() {
16383 if (!mods.length) {
16384 Roo.debug && Roo.log('hide?');
16385 if (!this.hideProgress && Roo.MessageBox) {
16386 Roo.MessageBox.hide();
16388 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16390 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16396 var m = mods.shift();
16399 Roo.debug && Roo.log(m);
16400 // not sure if this is supported any more.. - modules that are are just function
16401 if (typeof(m) == 'function') {
16403 return progressRun.defer(10, _this);
16407 msg = "Building Interface " + (total - mods.length) +
16409 (m.name ? (' - ' + m.name) : '');
16410 Roo.debug && Roo.log(msg);
16411 if (!this.hideProgress && Roo.MessageBox) {
16412 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16416 // is the module disabled?
16417 var disabled = (typeof(m.disabled) == 'function') ?
16418 m.disabled.call(m.module.disabled) : m.disabled;
16422 return progressRun(); // we do not update the display!
16430 // it's 10 on top level, and 1 on others??? why...
16431 return progressRun.defer(10, _this);
16434 progressRun.defer(1, _this);
16448 * wrapper for event.on - aliased later..
16449 * Typically use to register a event handler for register:
16451 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16460 Roo.XComponent.event = new Roo.util.Observable({
16464 * Fires when an Component is registered,
16465 * set the disable property on the Component to stop registration.
16466 * @param {Roo.XComponent} c the component being registerd.
16471 * @event beforebuild
16472 * Fires before each Component is built
16473 * can be used to apply permissions.
16474 * @param {Roo.XComponent} c the component being registerd.
16477 'beforebuild' : true,
16479 * @event buildcomplete
16480 * Fires on the top level element when all elements have been built
16481 * @param {Roo.XComponent} the top level component.
16483 'buildcomplete' : true
16488 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16491 * marked - a markdown parser
16492 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16493 * https://github.com/chjj/marked
16499 * Roo.Markdown - is a very crude wrapper around marked..
16503 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16505 * Note: move the sample code to the bottom of this
16506 * file before uncommenting it.
16511 Roo.Markdown.toHtml = function(text) {
16513 var c = new Roo.Markdown.marked.setOptions({
16514 renderer: new Roo.Markdown.marked.Renderer(),
16525 text = text.replace(/\\\n/g,' ');
16526 return Roo.Markdown.marked(text);
16531 // Wraps all "globals" so that the only thing
16532 // exposed is makeHtml().
16537 * Block-Level Grammar
16542 code: /^( {4}[^\n]+\n*)+/,
16544 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16545 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16547 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16548 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16549 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16550 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16551 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16553 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16557 block.bullet = /(?:[*+-]|\d+\.)/;
16558 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16559 block.item = replace(block.item, 'gm')
16560 (/bull/g, block.bullet)
16563 block.list = replace(block.list)
16564 (/bull/g, block.bullet)
16565 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16566 ('def', '\\n+(?=' + block.def.source + ')')
16569 block.blockquote = replace(block.blockquote)
16573 block._tag = '(?!(?:'
16574 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16575 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16576 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16578 block.html = replace(block.html)
16579 ('comment', /<!--[\s\S]*?-->/)
16580 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16581 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16582 (/tag/g, block._tag)
16585 block.paragraph = replace(block.paragraph)
16587 ('heading', block.heading)
16588 ('lheading', block.lheading)
16589 ('blockquote', block.blockquote)
16590 ('tag', '<' + block._tag)
16595 * Normal Block Grammar
16598 block.normal = merge({}, block);
16601 * GFM Block Grammar
16604 block.gfm = merge({}, block.normal, {
16605 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16607 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16610 block.gfm.paragraph = replace(block.paragraph)
16612 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16613 + block.list.source.replace('\\1', '\\3') + '|')
16617 * GFM + Tables Block Grammar
16620 block.tables = merge({}, block.gfm, {
16621 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16622 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16629 function Lexer(options) {
16631 this.tokens.links = {};
16632 this.options = options || marked.defaults;
16633 this.rules = block.normal;
16635 if (this.options.gfm) {
16636 if (this.options.tables) {
16637 this.rules = block.tables;
16639 this.rules = block.gfm;
16645 * Expose Block Rules
16648 Lexer.rules = block;
16651 * Static Lex Method
16654 Lexer.lex = function(src, options) {
16655 var lexer = new Lexer(options);
16656 return lexer.lex(src);
16663 Lexer.prototype.lex = function(src) {
16665 .replace(/\r\n|\r/g, '\n')
16666 .replace(/\t/g, ' ')
16667 .replace(/\u00a0/g, ' ')
16668 .replace(/\u2424/g, '\n');
16670 return this.token(src, true);
16677 Lexer.prototype.token = function(src, top, bq) {
16678 var src = src.replace(/^ +$/gm, '')
16691 if (cap = this.rules.newline.exec(src)) {
16692 src = src.substring(cap[0].length);
16693 if (cap[0].length > 1) {
16701 if (cap = this.rules.code.exec(src)) {
16702 src = src.substring(cap[0].length);
16703 cap = cap[0].replace(/^ {4}/gm, '');
16706 text: !this.options.pedantic
16707 ? cap.replace(/\n+$/, '')
16714 if (cap = this.rules.fences.exec(src)) {
16715 src = src.substring(cap[0].length);
16725 if (cap = this.rules.heading.exec(src)) {
16726 src = src.substring(cap[0].length);
16729 depth: cap[1].length,
16735 // table no leading pipe (gfm)
16736 if (top && (cap = this.rules.nptable.exec(src))) {
16737 src = src.substring(cap[0].length);
16741 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16742 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16743 cells: cap[3].replace(/\n$/, '').split('\n')
16746 for (i = 0; i < item.align.length; i++) {
16747 if (/^ *-+: *$/.test(item.align[i])) {
16748 item.align[i] = 'right';
16749 } else if (/^ *:-+: *$/.test(item.align[i])) {
16750 item.align[i] = 'center';
16751 } else if (/^ *:-+ *$/.test(item.align[i])) {
16752 item.align[i] = 'left';
16754 item.align[i] = null;
16758 for (i = 0; i < item.cells.length; i++) {
16759 item.cells[i] = item.cells[i].split(/ *\| */);
16762 this.tokens.push(item);
16768 if (cap = this.rules.lheading.exec(src)) {
16769 src = src.substring(cap[0].length);
16772 depth: cap[2] === '=' ? 1 : 2,
16779 if (cap = this.rules.hr.exec(src)) {
16780 src = src.substring(cap[0].length);
16788 if (cap = this.rules.blockquote.exec(src)) {
16789 src = src.substring(cap[0].length);
16792 type: 'blockquote_start'
16795 cap = cap[0].replace(/^ *> ?/gm, '');
16797 // Pass `top` to keep the current
16798 // "toplevel" state. This is exactly
16799 // how markdown.pl works.
16800 this.token(cap, top, true);
16803 type: 'blockquote_end'
16810 if (cap = this.rules.list.exec(src)) {
16811 src = src.substring(cap[0].length);
16815 type: 'list_start',
16816 ordered: bull.length > 1
16819 // Get each top-level item.
16820 cap = cap[0].match(this.rules.item);
16826 for (; i < l; i++) {
16829 // Remove the list item's bullet
16830 // so it is seen as the next token.
16831 space = item.length;
16832 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16834 // Outdent whatever the
16835 // list item contains. Hacky.
16836 if (~item.indexOf('\n ')) {
16837 space -= item.length;
16838 item = !this.options.pedantic
16839 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16840 : item.replace(/^ {1,4}/gm, '');
16843 // Determine whether the next list item belongs here.
16844 // Backpedal if it does not belong in this list.
16845 if (this.options.smartLists && i !== l - 1) {
16846 b = block.bullet.exec(cap[i + 1])[0];
16847 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16848 src = cap.slice(i + 1).join('\n') + src;
16853 // Determine whether item is loose or not.
16854 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16855 // for discount behavior.
16856 loose = next || /\n\n(?!\s*$)/.test(item);
16858 next = item.charAt(item.length - 1) === '\n';
16859 if (!loose) { loose = next; }
16864 ? 'loose_item_start'
16865 : 'list_item_start'
16869 this.token(item, false, bq);
16872 type: 'list_item_end'
16884 if (cap = this.rules.html.exec(src)) {
16885 src = src.substring(cap[0].length);
16887 type: this.options.sanitize
16890 pre: !this.options.sanitizer
16891 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
16898 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
16899 src = src.substring(cap[0].length);
16900 this.tokens.links[cap[1].toLowerCase()] = {
16908 if (top && (cap = this.rules.table.exec(src))) {
16909 src = src.substring(cap[0].length);
16913 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16914 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16915 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
16918 for (i = 0; i < item.align.length; i++) {
16919 if (/^ *-+: *$/.test(item.align[i])) {
16920 item.align[i] = 'right';
16921 } else if (/^ *:-+: *$/.test(item.align[i])) {
16922 item.align[i] = 'center';
16923 } else if (/^ *:-+ *$/.test(item.align[i])) {
16924 item.align[i] = 'left';
16926 item.align[i] = null;
16930 for (i = 0; i < item.cells.length; i++) {
16931 item.cells[i] = item.cells[i]
16932 .replace(/^ *\| *| *\| *$/g, '')
16936 this.tokens.push(item);
16941 // top-level paragraph
16942 if (top && (cap = this.rules.paragraph.exec(src))) {
16943 src = src.substring(cap[0].length);
16946 text: cap[1].charAt(cap[1].length - 1) === '\n'
16947 ? cap[1].slice(0, -1)
16954 if (cap = this.rules.text.exec(src)) {
16955 // Top-level should never reach here.
16956 src = src.substring(cap[0].length);
16966 Error('Infinite loop on byte: ' + src.charCodeAt(0));
16970 return this.tokens;
16974 * Inline-Level Grammar
16978 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
16979 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
16981 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
16982 link: /^!?\[(inside)\]\(href\)/,
16983 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
16984 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
16985 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
16986 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
16987 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
16988 br: /^ {2,}\n(?!\s*$)/,
16990 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
16993 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
16994 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
16996 inline.link = replace(inline.link)
16997 ('inside', inline._inside)
16998 ('href', inline._href)
17001 inline.reflink = replace(inline.reflink)
17002 ('inside', inline._inside)
17006 * Normal Inline Grammar
17009 inline.normal = merge({}, inline);
17012 * Pedantic Inline Grammar
17015 inline.pedantic = merge({}, inline.normal, {
17016 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17017 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17021 * GFM Inline Grammar
17024 inline.gfm = merge({}, inline.normal, {
17025 escape: replace(inline.escape)('])', '~|])')(),
17026 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17027 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17028 text: replace(inline.text)
17030 ('|', '|https?://|')
17035 * GFM + Line Breaks Inline Grammar
17038 inline.breaks = merge({}, inline.gfm, {
17039 br: replace(inline.br)('{2,}', '*')(),
17040 text: replace(inline.gfm.text)('{2,}', '*')()
17044 * Inline Lexer & Compiler
17047 function InlineLexer(links, options) {
17048 this.options = options || marked.defaults;
17049 this.links = links;
17050 this.rules = inline.normal;
17051 this.renderer = this.options.renderer || new Renderer;
17052 this.renderer.options = this.options;
17056 Error('Tokens array requires a `links` property.');
17059 if (this.options.gfm) {
17060 if (this.options.breaks) {
17061 this.rules = inline.breaks;
17063 this.rules = inline.gfm;
17065 } else if (this.options.pedantic) {
17066 this.rules = inline.pedantic;
17071 * Expose Inline Rules
17074 InlineLexer.rules = inline;
17077 * Static Lexing/Compiling Method
17080 InlineLexer.output = function(src, links, options) {
17081 var inline = new InlineLexer(links, options);
17082 return inline.output(src);
17089 InlineLexer.prototype.output = function(src) {
17098 if (cap = this.rules.escape.exec(src)) {
17099 src = src.substring(cap[0].length);
17105 if (cap = this.rules.autolink.exec(src)) {
17106 src = src.substring(cap[0].length);
17107 if (cap[2] === '@') {
17108 text = cap[1].charAt(6) === ':'
17109 ? this.mangle(cap[1].substring(7))
17110 : this.mangle(cap[1]);
17111 href = this.mangle('mailto:') + text;
17113 text = escape(cap[1]);
17116 out += this.renderer.link(href, null, text);
17121 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17122 src = src.substring(cap[0].length);
17123 text = escape(cap[1]);
17125 out += this.renderer.link(href, null, text);
17130 if (cap = this.rules.tag.exec(src)) {
17131 if (!this.inLink && /^<a /i.test(cap[0])) {
17132 this.inLink = true;
17133 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17134 this.inLink = false;
17136 src = src.substring(cap[0].length);
17137 out += this.options.sanitize
17138 ? this.options.sanitizer
17139 ? this.options.sanitizer(cap[0])
17146 if (cap = this.rules.link.exec(src)) {
17147 src = src.substring(cap[0].length);
17148 this.inLink = true;
17149 out += this.outputLink(cap, {
17153 this.inLink = false;
17158 if ((cap = this.rules.reflink.exec(src))
17159 || (cap = this.rules.nolink.exec(src))) {
17160 src = src.substring(cap[0].length);
17161 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17162 link = this.links[link.toLowerCase()];
17163 if (!link || !link.href) {
17164 out += cap[0].charAt(0);
17165 src = cap[0].substring(1) + src;
17168 this.inLink = true;
17169 out += this.outputLink(cap, link);
17170 this.inLink = false;
17175 if (cap = this.rules.strong.exec(src)) {
17176 src = src.substring(cap[0].length);
17177 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17182 if (cap = this.rules.em.exec(src)) {
17183 src = src.substring(cap[0].length);
17184 out += this.renderer.em(this.output(cap[2] || cap[1]));
17189 if (cap = this.rules.code.exec(src)) {
17190 src = src.substring(cap[0].length);
17191 out += this.renderer.codespan(escape(cap[2], true));
17196 if (cap = this.rules.br.exec(src)) {
17197 src = src.substring(cap[0].length);
17198 out += this.renderer.br();
17203 if (cap = this.rules.del.exec(src)) {
17204 src = src.substring(cap[0].length);
17205 out += this.renderer.del(this.output(cap[1]));
17210 if (cap = this.rules.text.exec(src)) {
17211 src = src.substring(cap[0].length);
17212 out += this.renderer.text(escape(this.smartypants(cap[0])));
17218 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17229 InlineLexer.prototype.outputLink = function(cap, link) {
17230 var href = escape(link.href)
17231 , title = link.title ? escape(link.title) : null;
17233 return cap[0].charAt(0) !== '!'
17234 ? this.renderer.link(href, title, this.output(cap[1]))
17235 : this.renderer.image(href, title, escape(cap[1]));
17239 * Smartypants Transformations
17242 InlineLexer.prototype.smartypants = function(text) {
17243 if (!this.options.smartypants) { return text; }
17246 .replace(/---/g, '\u2014')
17248 .replace(/--/g, '\u2013')
17250 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17251 // closing singles & apostrophes
17252 .replace(/'/g, '\u2019')
17254 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17256 .replace(/"/g, '\u201d')
17258 .replace(/\.{3}/g, '\u2026');
17265 InlineLexer.prototype.mangle = function(text) {
17266 if (!this.options.mangle) { return text; }
17272 for (; i < l; i++) {
17273 ch = text.charCodeAt(i);
17274 if (Math.random() > 0.5) {
17275 ch = 'x' + ch.toString(16);
17277 out += '&#' + ch + ';';
17287 function Renderer(options) {
17288 this.options = options || {};
17291 Renderer.prototype.code = function(code, lang, escaped) {
17292 if (this.options.highlight) {
17293 var out = this.options.highlight(code, lang);
17294 if (out != null && out !== code) {
17299 // hack!!! - it's already escapeD?
17304 return '<pre><code>'
17305 + (escaped ? code : escape(code, true))
17306 + '\n</code></pre>';
17309 return '<pre><code class="'
17310 + this.options.langPrefix
17311 + escape(lang, true)
17313 + (escaped ? code : escape(code, true))
17314 + '\n</code></pre>\n';
17317 Renderer.prototype.blockquote = function(quote) {
17318 return '<blockquote>\n' + quote + '</blockquote>\n';
17321 Renderer.prototype.html = function(html) {
17325 Renderer.prototype.heading = function(text, level, raw) {
17329 + this.options.headerPrefix
17330 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17338 Renderer.prototype.hr = function() {
17339 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17342 Renderer.prototype.list = function(body, ordered) {
17343 var type = ordered ? 'ol' : 'ul';
17344 return '<' + type + '>\n' + body + '</' + type + '>\n';
17347 Renderer.prototype.listitem = function(text) {
17348 return '<li>' + text + '</li>\n';
17351 Renderer.prototype.paragraph = function(text) {
17352 return '<p>' + text + '</p>\n';
17355 Renderer.prototype.table = function(header, body) {
17356 return '<table class="table table-striped">\n'
17366 Renderer.prototype.tablerow = function(content) {
17367 return '<tr>\n' + content + '</tr>\n';
17370 Renderer.prototype.tablecell = function(content, flags) {
17371 var type = flags.header ? 'th' : 'td';
17372 var tag = flags.align
17373 ? '<' + type + ' style="text-align:' + flags.align + '">'
17374 : '<' + type + '>';
17375 return tag + content + '</' + type + '>\n';
17378 // span level renderer
17379 Renderer.prototype.strong = function(text) {
17380 return '<strong>' + text + '</strong>';
17383 Renderer.prototype.em = function(text) {
17384 return '<em>' + text + '</em>';
17387 Renderer.prototype.codespan = function(text) {
17388 return '<code>' + text + '</code>';
17391 Renderer.prototype.br = function() {
17392 return this.options.xhtml ? '<br/>' : '<br>';
17395 Renderer.prototype.del = function(text) {
17396 return '<del>' + text + '</del>';
17399 Renderer.prototype.link = function(href, title, text) {
17400 if (this.options.sanitize) {
17402 var prot = decodeURIComponent(unescape(href))
17403 .replace(/[^\w:]/g, '')
17408 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17412 var out = '<a href="' + href + '"';
17414 out += ' title="' + title + '"';
17416 out += '>' + text + '</a>';
17420 Renderer.prototype.image = function(href, title, text) {
17421 var out = '<img src="' + href + '" alt="' + text + '"';
17423 out += ' title="' + title + '"';
17425 out += this.options.xhtml ? '/>' : '>';
17429 Renderer.prototype.text = function(text) {
17434 * Parsing & Compiling
17437 function Parser(options) {
17440 this.options = options || marked.defaults;
17441 this.options.renderer = this.options.renderer || new Renderer;
17442 this.renderer = this.options.renderer;
17443 this.renderer.options = this.options;
17447 * Static Parse Method
17450 Parser.parse = function(src, options, renderer) {
17451 var parser = new Parser(options, renderer);
17452 return parser.parse(src);
17459 Parser.prototype.parse = function(src) {
17460 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17461 this.tokens = src.reverse();
17464 while (this.next()) {
17475 Parser.prototype.next = function() {
17476 return this.token = this.tokens.pop();
17480 * Preview Next Token
17483 Parser.prototype.peek = function() {
17484 return this.tokens[this.tokens.length - 1] || 0;
17488 * Parse Text Tokens
17491 Parser.prototype.parseText = function() {
17492 var body = this.token.text;
17494 while (this.peek().type === 'text') {
17495 body += '\n' + this.next().text;
17498 return this.inline.output(body);
17502 * Parse Current Token
17505 Parser.prototype.tok = function() {
17506 switch (this.token.type) {
17511 return this.renderer.hr();
17514 return this.renderer.heading(
17515 this.inline.output(this.token.text),
17520 return this.renderer.code(this.token.text,
17522 this.token.escaped);
17535 for (i = 0; i < this.token.header.length; i++) {
17536 flags = { header: true, align: this.token.align[i] };
17537 cell += this.renderer.tablecell(
17538 this.inline.output(this.token.header[i]),
17539 { header: true, align: this.token.align[i] }
17542 header += this.renderer.tablerow(cell);
17544 for (i = 0; i < this.token.cells.length; i++) {
17545 row = this.token.cells[i];
17548 for (j = 0; j < row.length; j++) {
17549 cell += this.renderer.tablecell(
17550 this.inline.output(row[j]),
17551 { header: false, align: this.token.align[j] }
17555 body += this.renderer.tablerow(cell);
17557 return this.renderer.table(header, body);
17559 case 'blockquote_start': {
17562 while (this.next().type !== 'blockquote_end') {
17563 body += this.tok();
17566 return this.renderer.blockquote(body);
17568 case 'list_start': {
17570 , ordered = this.token.ordered;
17572 while (this.next().type !== 'list_end') {
17573 body += this.tok();
17576 return this.renderer.list(body, ordered);
17578 case 'list_item_start': {
17581 while (this.next().type !== 'list_item_end') {
17582 body += this.token.type === 'text'
17587 return this.renderer.listitem(body);
17589 case 'loose_item_start': {
17592 while (this.next().type !== 'list_item_end') {
17593 body += this.tok();
17596 return this.renderer.listitem(body);
17599 var html = !this.token.pre && !this.options.pedantic
17600 ? this.inline.output(this.token.text)
17602 return this.renderer.html(html);
17604 case 'paragraph': {
17605 return this.renderer.paragraph(this.inline.output(this.token.text));
17608 return this.renderer.paragraph(this.parseText());
17617 function escape(html, encode) {
17619 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17620 .replace(/</g, '<')
17621 .replace(/>/g, '>')
17622 .replace(/"/g, '"')
17623 .replace(/'/g, ''');
17626 function unescape(html) {
17627 // explicitly match decimal, hex, and named HTML entities
17628 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17629 n = n.toLowerCase();
17630 if (n === 'colon') { return ':'; }
17631 if (n.charAt(0) === '#') {
17632 return n.charAt(1) === 'x'
17633 ? String.fromCharCode(parseInt(n.substring(2), 16))
17634 : String.fromCharCode(+n.substring(1));
17640 function replace(regex, opt) {
17641 regex = regex.source;
17643 return function self(name, val) {
17644 if (!name) { return new RegExp(regex, opt); }
17645 val = val.source || val;
17646 val = val.replace(/(^|[^\[])\^/g, '$1');
17647 regex = regex.replace(name, val);
17655 function merge(obj) {
17660 for (; i < arguments.length; i++) {
17661 target = arguments[i];
17662 for (key in target) {
17663 if (Object.prototype.hasOwnProperty.call(target, key)) {
17664 obj[key] = target[key];
17677 function marked(src, opt, callback) {
17678 if (callback || typeof opt === 'function') {
17684 opt = merge({}, marked.defaults, opt || {});
17686 var highlight = opt.highlight
17692 tokens = Lexer.lex(src, opt)
17694 return callback(e);
17697 pending = tokens.length;
17699 var done = function(err) {
17701 opt.highlight = highlight;
17702 return callback(err);
17708 out = Parser.parse(tokens, opt);
17713 opt.highlight = highlight;
17717 : callback(null, out);
17720 if (!highlight || highlight.length < 3) {
17724 delete opt.highlight;
17726 if (!pending) { return done(); }
17728 for (; i < tokens.length; i++) {
17730 if (token.type !== 'code') {
17731 return --pending || done();
17733 return highlight(token.text, token.lang, function(err, code) {
17734 if (err) { return done(err); }
17735 if (code == null || code === token.text) {
17736 return --pending || done();
17739 token.escaped = true;
17740 --pending || done();
17748 if (opt) { opt = merge({}, marked.defaults, opt); }
17749 return Parser.parse(Lexer.lex(src, opt), opt);
17751 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17752 if ((opt || marked.defaults).silent) {
17753 return '<p>An error occured:</p><pre>'
17754 + escape(e.message + '', true)
17766 marked.setOptions = function(opt) {
17767 merge(marked.defaults, opt);
17771 marked.defaults = {
17782 langPrefix: 'lang-',
17783 smartypants: false,
17785 renderer: new Renderer,
17793 marked.Parser = Parser;
17794 marked.parser = Parser.parse;
17796 marked.Renderer = Renderer;
17798 marked.Lexer = Lexer;
17799 marked.lexer = Lexer.lex;
17801 marked.InlineLexer = InlineLexer;
17802 marked.inlineLexer = InlineLexer.output;
17804 marked.parse = marked;
17806 Roo.Markdown.marked = marked;
17810 * Ext JS Library 1.1.1
17811 * Copyright(c) 2006-2007, Ext JS, LLC.
17813 * Originally Released Under LGPL - original licence link has changed is not relivant.
17816 * <script type="text/javascript">
17822 * These classes are derivatives of the similarly named classes in the YUI Library.
17823 * The original license:
17824 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17825 * Code licensed under the BSD License:
17826 * http://developer.yahoo.net/yui/license.txt
17831 var Event=Roo.EventManager;
17832 var Dom=Roo.lib.Dom;
17835 * @class Roo.dd.DragDrop
17836 * @extends Roo.util.Observable
17837 * Defines the interface and base operation of items that that can be
17838 * dragged or can be drop targets. It was designed to be extended, overriding
17839 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17840 * Up to three html elements can be associated with a DragDrop instance:
17842 * <li>linked element: the element that is passed into the constructor.
17843 * This is the element which defines the boundaries for interaction with
17844 * other DragDrop objects.</li>
17845 * <li>handle element(s): The drag operation only occurs if the element that
17846 * was clicked matches a handle element. By default this is the linked
17847 * element, but there are times that you will want only a portion of the
17848 * linked element to initiate the drag operation, and the setHandleElId()
17849 * method provides a way to define this.</li>
17850 * <li>drag element: this represents the element that would be moved along
17851 * with the cursor during a drag operation. By default, this is the linked
17852 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17853 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17856 * This class should not be instantiated until the onload event to ensure that
17857 * the associated elements are available.
17858 * The following would define a DragDrop obj that would interact with any
17859 * other DragDrop obj in the "group1" group:
17861 * dd = new Roo.dd.DragDrop("div1", "group1");
17863 * Since none of the event handlers have been implemented, nothing would
17864 * actually happen if you were to run the code above. Normally you would
17865 * override this class or one of the default implementations, but you can
17866 * also override the methods you want on an instance of the class...
17868 * dd.onDragDrop = function(e, id) {
17869 * alert("dd was dropped on " + id);
17873 * @param {String} id of the element that is linked to this instance
17874 * @param {String} sGroup the group of related DragDrop objects
17875 * @param {object} config an object containing configurable attributes
17876 * Valid properties for DragDrop:
17877 * padding, isTarget, maintainOffset, primaryButtonOnly
17879 Roo.dd.DragDrop = function(id, sGroup, config) {
17881 this.init(id, sGroup, config);
17886 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17889 * The id of the element associated with this object. This is what we
17890 * refer to as the "linked element" because the size and position of
17891 * this element is used to determine when the drag and drop objects have
17899 * Configuration attributes passed into the constructor
17906 * The id of the element that will be dragged. By default this is same
17907 * as the linked element , but could be changed to another element. Ex:
17909 * @property dragElId
17916 * the id of the element that initiates the drag operation. By default
17917 * this is the linked element, but could be changed to be a child of this
17918 * element. This lets us do things like only starting the drag when the
17919 * header element within the linked html element is clicked.
17920 * @property handleElId
17927 * An associative array of HTML tags that will be ignored if clicked.
17928 * @property invalidHandleTypes
17929 * @type {string: string}
17931 invalidHandleTypes: null,
17934 * An associative array of ids for elements that will be ignored if clicked
17935 * @property invalidHandleIds
17936 * @type {string: string}
17938 invalidHandleIds: null,
17941 * An indexted array of css class names for elements that will be ignored
17943 * @property invalidHandleClasses
17946 invalidHandleClasses: null,
17949 * The linked element's absolute X position at the time the drag was
17951 * @property startPageX
17958 * The linked element's absolute X position at the time the drag was
17960 * @property startPageY
17967 * The group defines a logical collection of DragDrop objects that are
17968 * related. Instances only get events when interacting with other
17969 * DragDrop object in the same group. This lets us define multiple
17970 * groups using a single DragDrop subclass if we want.
17972 * @type {string: string}
17977 * Individual drag/drop instances can be locked. This will prevent
17978 * onmousedown start drag.
17986 * Lock this instance
17989 lock: function() { this.locked = true; },
17992 * Unlock this instace
17995 unlock: function() { this.locked = false; },
17998 * By default, all insances can be a drop target. This can be disabled by
17999 * setting isTarget to false.
18006 * The padding configured for this drag and drop object for calculating
18007 * the drop zone intersection with this object.
18014 * Cached reference to the linked element
18015 * @property _domRef
18021 * Internal typeof flag
18022 * @property __ygDragDrop
18025 __ygDragDrop: true,
18028 * Set to true when horizontal contraints are applied
18029 * @property constrainX
18036 * Set to true when vertical contraints are applied
18037 * @property constrainY
18044 * The left constraint
18052 * The right constraint
18060 * The up constraint
18069 * The down constraint
18077 * Maintain offsets when we resetconstraints. Set to true when you want
18078 * the position of the element relative to its parent to stay the same
18079 * when the page changes
18081 * @property maintainOffset
18084 maintainOffset: false,
18087 * Array of pixel locations the element will snap to if we specified a
18088 * horizontal graduation/interval. This array is generated automatically
18089 * when you define a tick interval.
18096 * Array of pixel locations the element will snap to if we specified a
18097 * vertical graduation/interval. This array is generated automatically
18098 * when you define a tick interval.
18105 * By default the drag and drop instance will only respond to the primary
18106 * button click (left button for a right-handed mouse). Set to true to
18107 * allow drag and drop to start with any mouse click that is propogated
18109 * @property primaryButtonOnly
18112 primaryButtonOnly: true,
18115 * The availabe property is false until the linked dom element is accessible.
18116 * @property available
18122 * By default, drags can only be initiated if the mousedown occurs in the
18123 * region the linked element is. This is done in part to work around a
18124 * bug in some browsers that mis-report the mousedown if the previous
18125 * mouseup happened outside of the window. This property is set to true
18126 * if outer handles are defined.
18128 * @property hasOuterHandles
18132 hasOuterHandles: false,
18135 * Code that executes immediately before the startDrag event
18136 * @method b4StartDrag
18139 b4StartDrag: function(x, y) { },
18142 * Abstract method called after a drag/drop object is clicked
18143 * and the drag or mousedown time thresholds have beeen met.
18144 * @method startDrag
18145 * @param {int} X click location
18146 * @param {int} Y click location
18148 startDrag: function(x, y) { /* override this */ },
18151 * Code that executes immediately before the onDrag event
18155 b4Drag: function(e) { },
18158 * Abstract method called during the onMouseMove event while dragging an
18161 * @param {Event} e the mousemove event
18163 onDrag: function(e) { /* override this */ },
18166 * Abstract method called when this element fist begins hovering over
18167 * another DragDrop obj
18168 * @method onDragEnter
18169 * @param {Event} e the mousemove event
18170 * @param {String|DragDrop[]} id In POINT mode, the element
18171 * id this is hovering over. In INTERSECT mode, an array of one or more
18172 * dragdrop items being hovered over.
18174 onDragEnter: function(e, id) { /* override this */ },
18177 * Code that executes immediately before the onDragOver event
18178 * @method b4DragOver
18181 b4DragOver: function(e) { },
18184 * Abstract method called when this element is hovering over another
18186 * @method onDragOver
18187 * @param {Event} e the mousemove event
18188 * @param {String|DragDrop[]} id In POINT mode, the element
18189 * id this is hovering over. In INTERSECT mode, an array of dd items
18190 * being hovered over.
18192 onDragOver: function(e, id) { /* override this */ },
18195 * Code that executes immediately before the onDragOut event
18196 * @method b4DragOut
18199 b4DragOut: function(e) { },
18202 * Abstract method called when we are no longer hovering over an element
18203 * @method onDragOut
18204 * @param {Event} e the mousemove event
18205 * @param {String|DragDrop[]} id In POINT mode, the element
18206 * id this was hovering over. In INTERSECT mode, an array of dd items
18207 * that the mouse is no longer over.
18209 onDragOut: function(e, id) { /* override this */ },
18212 * Code that executes immediately before the onDragDrop event
18213 * @method b4DragDrop
18216 b4DragDrop: function(e) { },
18219 * Abstract method called when this item is dropped on another DragDrop
18221 * @method onDragDrop
18222 * @param {Event} e the mouseup event
18223 * @param {String|DragDrop[]} id In POINT mode, the element
18224 * id this was dropped on. In INTERSECT mode, an array of dd items this
18227 onDragDrop: function(e, id) { /* override this */ },
18230 * Abstract method called when this item is dropped on an area with no
18232 * @method onInvalidDrop
18233 * @param {Event} e the mouseup event
18235 onInvalidDrop: function(e) { /* override this */ },
18238 * Code that executes immediately before the endDrag event
18239 * @method b4EndDrag
18242 b4EndDrag: function(e) { },
18245 * Fired when we are done dragging the object
18247 * @param {Event} e the mouseup event
18249 endDrag: function(e) { /* override this */ },
18252 * Code executed immediately before the onMouseDown event
18253 * @method b4MouseDown
18254 * @param {Event} e the mousedown event
18257 b4MouseDown: function(e) { },
18260 * Event handler that fires when a drag/drop obj gets a mousedown
18261 * @method onMouseDown
18262 * @param {Event} e the mousedown event
18264 onMouseDown: function(e) { /* override this */ },
18267 * Event handler that fires when a drag/drop obj gets a mouseup
18268 * @method onMouseUp
18269 * @param {Event} e the mouseup event
18271 onMouseUp: function(e) { /* override this */ },
18274 * Override the onAvailable method to do what is needed after the initial
18275 * position was determined.
18276 * @method onAvailable
18278 onAvailable: function () {
18282 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18285 defaultPadding : {left:0, right:0, top:0, bottom:0},
18288 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18292 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18293 { dragElId: "existingProxyDiv" });
18294 dd.startDrag = function(){
18295 this.constrainTo("parent-id");
18298 * Or you can initalize it using the {@link Roo.Element} object:
18300 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18301 startDrag : function(){
18302 this.constrainTo("parent-id");
18306 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18307 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18308 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18309 * an object containing the sides to pad. For example: {right:10, bottom:10}
18310 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18312 constrainTo : function(constrainTo, pad, inContent){
18313 if(typeof pad == "number"){
18314 pad = {left: pad, right:pad, top:pad, bottom:pad};
18316 pad = pad || this.defaultPadding;
18317 var b = Roo.get(this.getEl()).getBox();
18318 var ce = Roo.get(constrainTo);
18319 var s = ce.getScroll();
18320 var c, cd = ce.dom;
18321 if(cd == document.body){
18322 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18325 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18329 var topSpace = b.y - c.y;
18330 var leftSpace = b.x - c.x;
18332 this.resetConstraints();
18333 this.setXConstraint(leftSpace - (pad.left||0), // left
18334 c.width - leftSpace - b.width - (pad.right||0) //right
18336 this.setYConstraint(topSpace - (pad.top||0), //top
18337 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18342 * Returns a reference to the linked element
18344 * @return {HTMLElement} the html element
18346 getEl: function() {
18347 if (!this._domRef) {
18348 this._domRef = Roo.getDom(this.id);
18351 return this._domRef;
18355 * Returns a reference to the actual element to drag. By default this is
18356 * the same as the html element, but it can be assigned to another
18357 * element. An example of this can be found in Roo.dd.DDProxy
18358 * @method getDragEl
18359 * @return {HTMLElement} the html element
18361 getDragEl: function() {
18362 return Roo.getDom(this.dragElId);
18366 * Sets up the DragDrop object. Must be called in the constructor of any
18367 * Roo.dd.DragDrop subclass
18369 * @param id the id of the linked element
18370 * @param {String} sGroup the group of related items
18371 * @param {object} config configuration attributes
18373 init: function(id, sGroup, config) {
18374 this.initTarget(id, sGroup, config);
18375 if (!Roo.isTouch) {
18376 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18378 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18379 // Event.on(this.id, "selectstart", Event.preventDefault);
18383 * Initializes Targeting functionality only... the object does not
18384 * get a mousedown handler.
18385 * @method initTarget
18386 * @param id the id of the linked element
18387 * @param {String} sGroup the group of related items
18388 * @param {object} config configuration attributes
18390 initTarget: function(id, sGroup, config) {
18392 // configuration attributes
18393 this.config = config || {};
18395 // create a local reference to the drag and drop manager
18396 this.DDM = Roo.dd.DDM;
18397 // initialize the groups array
18400 // assume that we have an element reference instead of an id if the
18401 // parameter is not a string
18402 if (typeof id !== "string") {
18409 // add to an interaction group
18410 this.addToGroup((sGroup) ? sGroup : "default");
18412 // We don't want to register this as the handle with the manager
18413 // so we just set the id rather than calling the setter.
18414 this.handleElId = id;
18416 // the linked element is the element that gets dragged by default
18417 this.setDragElId(id);
18419 // by default, clicked anchors will not start drag operations.
18420 this.invalidHandleTypes = { A: "A" };
18421 this.invalidHandleIds = {};
18422 this.invalidHandleClasses = [];
18424 this.applyConfig();
18426 this.handleOnAvailable();
18430 * Applies the configuration parameters that were passed into the constructor.
18431 * This is supposed to happen at each level through the inheritance chain. So
18432 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18433 * DragDrop in order to get all of the parameters that are available in
18435 * @method applyConfig
18437 applyConfig: function() {
18439 // configurable properties:
18440 // padding, isTarget, maintainOffset, primaryButtonOnly
18441 this.padding = this.config.padding || [0, 0, 0, 0];
18442 this.isTarget = (this.config.isTarget !== false);
18443 this.maintainOffset = (this.config.maintainOffset);
18444 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18449 * Executed when the linked element is available
18450 * @method handleOnAvailable
18453 handleOnAvailable: function() {
18454 this.available = true;
18455 this.resetConstraints();
18456 this.onAvailable();
18460 * Configures the padding for the target zone in px. Effectively expands
18461 * (or reduces) the virtual object size for targeting calculations.
18462 * Supports css-style shorthand; if only one parameter is passed, all sides
18463 * will have that padding, and if only two are passed, the top and bottom
18464 * will have the first param, the left and right the second.
18465 * @method setPadding
18466 * @param {int} iTop Top pad
18467 * @param {int} iRight Right pad
18468 * @param {int} iBot Bot pad
18469 * @param {int} iLeft Left pad
18471 setPadding: function(iTop, iRight, iBot, iLeft) {
18472 // this.padding = [iLeft, iRight, iTop, iBot];
18473 if (!iRight && 0 !== iRight) {
18474 this.padding = [iTop, iTop, iTop, iTop];
18475 } else if (!iBot && 0 !== iBot) {
18476 this.padding = [iTop, iRight, iTop, iRight];
18478 this.padding = [iTop, iRight, iBot, iLeft];
18483 * Stores the initial placement of the linked element.
18484 * @method setInitialPosition
18485 * @param {int} diffX the X offset, default 0
18486 * @param {int} diffY the Y offset, default 0
18488 setInitPosition: function(diffX, diffY) {
18489 var el = this.getEl();
18491 if (!this.DDM.verifyEl(el)) {
18495 var dx = diffX || 0;
18496 var dy = diffY || 0;
18498 var p = Dom.getXY( el );
18500 this.initPageX = p[0] - dx;
18501 this.initPageY = p[1] - dy;
18503 this.lastPageX = p[0];
18504 this.lastPageY = p[1];
18507 this.setStartPosition(p);
18511 * Sets the start position of the element. This is set when the obj
18512 * is initialized, the reset when a drag is started.
18513 * @method setStartPosition
18514 * @param pos current position (from previous lookup)
18517 setStartPosition: function(pos) {
18518 var p = pos || Dom.getXY( this.getEl() );
18519 this.deltaSetXY = null;
18521 this.startPageX = p[0];
18522 this.startPageY = p[1];
18526 * Add this instance to a group of related drag/drop objects. All
18527 * instances belong to at least one group, and can belong to as many
18528 * groups as needed.
18529 * @method addToGroup
18530 * @param sGroup {string} the name of the group
18532 addToGroup: function(sGroup) {
18533 this.groups[sGroup] = true;
18534 this.DDM.regDragDrop(this, sGroup);
18538 * Remove's this instance from the supplied interaction group
18539 * @method removeFromGroup
18540 * @param {string} sGroup The group to drop
18542 removeFromGroup: function(sGroup) {
18543 if (this.groups[sGroup]) {
18544 delete this.groups[sGroup];
18547 this.DDM.removeDDFromGroup(this, sGroup);
18551 * Allows you to specify that an element other than the linked element
18552 * will be moved with the cursor during a drag
18553 * @method setDragElId
18554 * @param id {string} the id of the element that will be used to initiate the drag
18556 setDragElId: function(id) {
18557 this.dragElId = id;
18561 * Allows you to specify a child of the linked element that should be
18562 * used to initiate the drag operation. An example of this would be if
18563 * you have a content div with text and links. Clicking anywhere in the
18564 * content area would normally start the drag operation. Use this method
18565 * to specify that an element inside of the content div is the element
18566 * that starts the drag operation.
18567 * @method setHandleElId
18568 * @param id {string} the id of the element that will be used to
18569 * initiate the drag.
18571 setHandleElId: function(id) {
18572 if (typeof id !== "string") {
18575 this.handleElId = id;
18576 this.DDM.regHandle(this.id, id);
18580 * Allows you to set an element outside of the linked element as a drag
18582 * @method setOuterHandleElId
18583 * @param id the id of the element that will be used to initiate the drag
18585 setOuterHandleElId: function(id) {
18586 if (typeof id !== "string") {
18589 Event.on(id, "mousedown",
18590 this.handleMouseDown, this);
18591 this.setHandleElId(id);
18593 this.hasOuterHandles = true;
18597 * Remove all drag and drop hooks for this element
18600 unreg: function() {
18601 Event.un(this.id, "mousedown",
18602 this.handleMouseDown);
18603 Event.un(this.id, "touchstart",
18604 this.handleMouseDown);
18605 this._domRef = null;
18606 this.DDM._remove(this);
18609 destroy : function(){
18614 * Returns true if this instance is locked, or the drag drop mgr is locked
18615 * (meaning that all drag/drop is disabled on the page.)
18617 * @return {boolean} true if this obj or all drag/drop is locked, else
18620 isLocked: function() {
18621 return (this.DDM.isLocked() || this.locked);
18625 * Fired when this object is clicked
18626 * @method handleMouseDown
18628 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18631 handleMouseDown: function(e, oDD){
18633 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18634 //Roo.log('not touch/ button !=0');
18637 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18638 return; // double touch..
18642 if (this.isLocked()) {
18643 //Roo.log('locked');
18647 this.DDM.refreshCache(this.groups);
18648 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18649 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18650 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18651 //Roo.log('no outer handes or not over target');
18654 // Roo.log('check validator');
18655 if (this.clickValidator(e)) {
18656 // Roo.log('validate success');
18657 // set the initial element position
18658 this.setStartPosition();
18661 this.b4MouseDown(e);
18662 this.onMouseDown(e);
18664 this.DDM.handleMouseDown(e, this);
18666 this.DDM.stopEvent(e);
18674 clickValidator: function(e) {
18675 var target = e.getTarget();
18676 return ( this.isValidHandleChild(target) &&
18677 (this.id == this.handleElId ||
18678 this.DDM.handleWasClicked(target, this.id)) );
18682 * Allows you to specify a tag name that should not start a drag operation
18683 * when clicked. This is designed to facilitate embedding links within a
18684 * drag handle that do something other than start the drag.
18685 * @method addInvalidHandleType
18686 * @param {string} tagName the type of element to exclude
18688 addInvalidHandleType: function(tagName) {
18689 var type = tagName.toUpperCase();
18690 this.invalidHandleTypes[type] = type;
18694 * Lets you to specify an element id for a child of a drag handle
18695 * that should not initiate a drag
18696 * @method addInvalidHandleId
18697 * @param {string} id the element id of the element you wish to ignore
18699 addInvalidHandleId: function(id) {
18700 if (typeof id !== "string") {
18703 this.invalidHandleIds[id] = id;
18707 * Lets you specify a css class of elements that will not initiate a drag
18708 * @method addInvalidHandleClass
18709 * @param {string} cssClass the class of the elements you wish to ignore
18711 addInvalidHandleClass: function(cssClass) {
18712 this.invalidHandleClasses.push(cssClass);
18716 * Unsets an excluded tag name set by addInvalidHandleType
18717 * @method removeInvalidHandleType
18718 * @param {string} tagName the type of element to unexclude
18720 removeInvalidHandleType: function(tagName) {
18721 var type = tagName.toUpperCase();
18722 // this.invalidHandleTypes[type] = null;
18723 delete this.invalidHandleTypes[type];
18727 * Unsets an invalid handle id
18728 * @method removeInvalidHandleId
18729 * @param {string} id the id of the element to re-enable
18731 removeInvalidHandleId: function(id) {
18732 if (typeof id !== "string") {
18735 delete this.invalidHandleIds[id];
18739 * Unsets an invalid css class
18740 * @method removeInvalidHandleClass
18741 * @param {string} cssClass the class of the element(s) you wish to
18744 removeInvalidHandleClass: function(cssClass) {
18745 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18746 if (this.invalidHandleClasses[i] == cssClass) {
18747 delete this.invalidHandleClasses[i];
18753 * Checks the tag exclusion list to see if this click should be ignored
18754 * @method isValidHandleChild
18755 * @param {HTMLElement} node the HTMLElement to evaluate
18756 * @return {boolean} true if this is a valid tag type, false if not
18758 isValidHandleChild: function(node) {
18761 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18764 nodeName = node.nodeName.toUpperCase();
18766 nodeName = node.nodeName;
18768 valid = valid && !this.invalidHandleTypes[nodeName];
18769 valid = valid && !this.invalidHandleIds[node.id];
18771 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18772 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18781 * Create the array of horizontal tick marks if an interval was specified
18782 * in setXConstraint().
18783 * @method setXTicks
18786 setXTicks: function(iStartX, iTickSize) {
18788 this.xTickSize = iTickSize;
18792 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18794 this.xTicks[this.xTicks.length] = i;
18799 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18801 this.xTicks[this.xTicks.length] = i;
18806 this.xTicks.sort(this.DDM.numericSort) ;
18810 * Create the array of vertical tick marks if an interval was specified in
18811 * setYConstraint().
18812 * @method setYTicks
18815 setYTicks: function(iStartY, iTickSize) {
18817 this.yTickSize = iTickSize;
18821 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18823 this.yTicks[this.yTicks.length] = i;
18828 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18830 this.yTicks[this.yTicks.length] = i;
18835 this.yTicks.sort(this.DDM.numericSort) ;
18839 * By default, the element can be dragged any place on the screen. Use
18840 * this method to limit the horizontal travel of the element. Pass in
18841 * 0,0 for the parameters if you want to lock the drag to the y axis.
18842 * @method setXConstraint
18843 * @param {int} iLeft the number of pixels the element can move to the left
18844 * @param {int} iRight the number of pixels the element can move to the
18846 * @param {int} iTickSize optional parameter for specifying that the
18848 * should move iTickSize pixels at a time.
18850 setXConstraint: function(iLeft, iRight, iTickSize) {
18851 this.leftConstraint = iLeft;
18852 this.rightConstraint = iRight;
18854 this.minX = this.initPageX - iLeft;
18855 this.maxX = this.initPageX + iRight;
18856 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18858 this.constrainX = true;
18862 * Clears any constraints applied to this instance. Also clears ticks
18863 * since they can't exist independent of a constraint at this time.
18864 * @method clearConstraints
18866 clearConstraints: function() {
18867 this.constrainX = false;
18868 this.constrainY = false;
18873 * Clears any tick interval defined for this instance
18874 * @method clearTicks
18876 clearTicks: function() {
18877 this.xTicks = null;
18878 this.yTicks = null;
18879 this.xTickSize = 0;
18880 this.yTickSize = 0;
18884 * By default, the element can be dragged any place on the screen. Set
18885 * this to limit the vertical travel of the element. Pass in 0,0 for the
18886 * parameters if you want to lock the drag to the x axis.
18887 * @method setYConstraint
18888 * @param {int} iUp the number of pixels the element can move up
18889 * @param {int} iDown the number of pixels the element can move down
18890 * @param {int} iTickSize optional parameter for specifying that the
18891 * element should move iTickSize pixels at a time.
18893 setYConstraint: function(iUp, iDown, iTickSize) {
18894 this.topConstraint = iUp;
18895 this.bottomConstraint = iDown;
18897 this.minY = this.initPageY - iUp;
18898 this.maxY = this.initPageY + iDown;
18899 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
18901 this.constrainY = true;
18906 * resetConstraints must be called if you manually reposition a dd element.
18907 * @method resetConstraints
18908 * @param {boolean} maintainOffset
18910 resetConstraints: function() {
18913 // Maintain offsets if necessary
18914 if (this.initPageX || this.initPageX === 0) {
18915 // figure out how much this thing has moved
18916 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
18917 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
18919 this.setInitPosition(dx, dy);
18921 // This is the first time we have detected the element's position
18923 this.setInitPosition();
18926 if (this.constrainX) {
18927 this.setXConstraint( this.leftConstraint,
18928 this.rightConstraint,
18932 if (this.constrainY) {
18933 this.setYConstraint( this.topConstraint,
18934 this.bottomConstraint,
18940 * Normally the drag element is moved pixel by pixel, but we can specify
18941 * that it move a number of pixels at a time. This method resolves the
18942 * location when we have it set up like this.
18944 * @param {int} val where we want to place the object
18945 * @param {int[]} tickArray sorted array of valid points
18946 * @return {int} the closest tick
18949 getTick: function(val, tickArray) {
18952 // If tick interval is not defined, it is effectively 1 pixel,
18953 // so we return the value passed to us.
18955 } else if (tickArray[0] >= val) {
18956 // The value is lower than the first tick, so we return the first
18958 return tickArray[0];
18960 for (var i=0, len=tickArray.length; i<len; ++i) {
18962 if (tickArray[next] && tickArray[next] >= val) {
18963 var diff1 = val - tickArray[i];
18964 var diff2 = tickArray[next] - val;
18965 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
18969 // The value is larger than the last tick, so we return the last
18971 return tickArray[tickArray.length - 1];
18978 * @return {string} string representation of the dd obj
18980 toString: function() {
18981 return ("DragDrop " + this.id);
18989 * Ext JS Library 1.1.1
18990 * Copyright(c) 2006-2007, Ext JS, LLC.
18992 * Originally Released Under LGPL - original licence link has changed is not relivant.
18995 * <script type="text/javascript">
19000 * The drag and drop utility provides a framework for building drag and drop
19001 * applications. In addition to enabling drag and drop for specific elements,
19002 * the drag and drop elements are tracked by the manager class, and the
19003 * interactions between the various elements are tracked during the drag and
19004 * the implementing code is notified about these important moments.
19007 // Only load the library once. Rewriting the manager class would orphan
19008 // existing drag and drop instances.
19009 if (!Roo.dd.DragDropMgr) {
19012 * @class Roo.dd.DragDropMgr
19013 * DragDropMgr is a singleton that tracks the element interaction for
19014 * all DragDrop items in the window. Generally, you will not call
19015 * this class directly, but it does have helper methods that could
19016 * be useful in your DragDrop implementations.
19019 Roo.dd.DragDropMgr = function() {
19021 var Event = Roo.EventManager;
19026 * Two dimensional Array of registered DragDrop objects. The first
19027 * dimension is the DragDrop item group, the second the DragDrop
19030 * @type {string: string}
19037 * Array of element ids defined as drag handles. Used to determine
19038 * if the element that generated the mousedown event is actually the
19039 * handle and not the html element itself.
19040 * @property handleIds
19041 * @type {string: string}
19048 * the DragDrop object that is currently being dragged
19049 * @property dragCurrent
19057 * the DragDrop object(s) that are being hovered over
19058 * @property dragOvers
19066 * the X distance between the cursor and the object being dragged
19075 * the Y distance between the cursor and the object being dragged
19084 * Flag to determine if we should prevent the default behavior of the
19085 * events we define. By default this is true, but this can be set to
19086 * false if you need the default behavior (not recommended)
19087 * @property preventDefault
19091 preventDefault: true,
19094 * Flag to determine if we should stop the propagation of the events
19095 * we generate. This is true by default but you may want to set it to
19096 * false if the html element contains other features that require the
19098 * @property stopPropagation
19102 stopPropagation: true,
19105 * Internal flag that is set to true when drag and drop has been
19107 * @property initialized
19114 * All drag and drop can be disabled.
19122 * Called the first time an element is registered.
19128 this.initialized = true;
19132 * In point mode, drag and drop interaction is defined by the
19133 * location of the cursor during the drag/drop
19141 * In intersect mode, drag and drop interactio nis defined by the
19142 * overlap of two or more drag and drop objects.
19143 * @property INTERSECT
19150 * The current drag and drop mode. Default: POINT
19158 * Runs method on all drag and drop objects
19159 * @method _execOnAll
19163 _execOnAll: function(sMethod, args) {
19164 for (var i in this.ids) {
19165 for (var j in this.ids[i]) {
19166 var oDD = this.ids[i][j];
19167 if (! this.isTypeOfDD(oDD)) {
19170 oDD[sMethod].apply(oDD, args);
19176 * Drag and drop initialization. Sets up the global event handlers
19181 _onLoad: function() {
19185 if (!Roo.isTouch) {
19186 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19187 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19189 Event.on(document, "touchend", this.handleMouseUp, this, true);
19190 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19192 Event.on(window, "unload", this._onUnload, this, true);
19193 Event.on(window, "resize", this._onResize, this, true);
19194 // Event.on(window, "mouseout", this._test);
19199 * Reset constraints on all drag and drop objs
19200 * @method _onResize
19204 _onResize: function(e) {
19205 this._execOnAll("resetConstraints", []);
19209 * Lock all drag and drop functionality
19213 lock: function() { this.locked = true; },
19216 * Unlock all drag and drop functionality
19220 unlock: function() { this.locked = false; },
19223 * Is drag and drop locked?
19225 * @return {boolean} True if drag and drop is locked, false otherwise.
19228 isLocked: function() { return this.locked; },
19231 * Location cache that is set for all drag drop objects when a drag is
19232 * initiated, cleared when the drag is finished.
19233 * @property locationCache
19240 * Set useCache to false if you want to force object the lookup of each
19241 * drag and drop linked element constantly during a drag.
19242 * @property useCache
19249 * The number of pixels that the mouse needs to move after the
19250 * mousedown before the drag is initiated. Default=3;
19251 * @property clickPixelThresh
19255 clickPixelThresh: 3,
19258 * The number of milliseconds after the mousedown event to initiate the
19259 * drag if we don't get a mouseup event. Default=1000
19260 * @property clickTimeThresh
19264 clickTimeThresh: 350,
19267 * Flag that indicates that either the drag pixel threshold or the
19268 * mousdown time threshold has been met
19269 * @property dragThreshMet
19274 dragThreshMet: false,
19277 * Timeout used for the click time threshold
19278 * @property clickTimeout
19283 clickTimeout: null,
19286 * The X position of the mousedown event stored for later use when a
19287 * drag threshold is met.
19296 * The Y position of the mousedown event stored for later use when a
19297 * drag threshold is met.
19306 * Each DragDrop instance must be registered with the DragDropMgr.
19307 * This is executed in DragDrop.init()
19308 * @method regDragDrop
19309 * @param {DragDrop} oDD the DragDrop object to register
19310 * @param {String} sGroup the name of the group this element belongs to
19313 regDragDrop: function(oDD, sGroup) {
19314 if (!this.initialized) { this.init(); }
19316 if (!this.ids[sGroup]) {
19317 this.ids[sGroup] = {};
19319 this.ids[sGroup][oDD.id] = oDD;
19323 * Removes the supplied dd instance from the supplied group. Executed
19324 * by DragDrop.removeFromGroup, so don't call this function directly.
19325 * @method removeDDFromGroup
19329 removeDDFromGroup: function(oDD, sGroup) {
19330 if (!this.ids[sGroup]) {
19331 this.ids[sGroup] = {};
19334 var obj = this.ids[sGroup];
19335 if (obj && obj[oDD.id]) {
19336 delete obj[oDD.id];
19341 * Unregisters a drag and drop item. This is executed in
19342 * DragDrop.unreg, use that method instead of calling this directly.
19347 _remove: function(oDD) {
19348 for (var g in oDD.groups) {
19349 if (g && this.ids[g][oDD.id]) {
19350 delete this.ids[g][oDD.id];
19353 delete this.handleIds[oDD.id];
19357 * Each DragDrop handle element must be registered. This is done
19358 * automatically when executing DragDrop.setHandleElId()
19359 * @method regHandle
19360 * @param {String} sDDId the DragDrop id this element is a handle for
19361 * @param {String} sHandleId the id of the element that is the drag
19365 regHandle: function(sDDId, sHandleId) {
19366 if (!this.handleIds[sDDId]) {
19367 this.handleIds[sDDId] = {};
19369 this.handleIds[sDDId][sHandleId] = sHandleId;
19373 * Utility function to determine if a given element has been
19374 * registered as a drag drop item.
19375 * @method isDragDrop
19376 * @param {String} id the element id to check
19377 * @return {boolean} true if this element is a DragDrop item,
19381 isDragDrop: function(id) {
19382 return ( this.getDDById(id) ) ? true : false;
19386 * Returns the drag and drop instances that are in all groups the
19387 * passed in instance belongs to.
19388 * @method getRelated
19389 * @param {DragDrop} p_oDD the obj to get related data for
19390 * @param {boolean} bTargetsOnly if true, only return targetable objs
19391 * @return {DragDrop[]} the related instances
19394 getRelated: function(p_oDD, bTargetsOnly) {
19396 for (var i in p_oDD.groups) {
19397 for (j in this.ids[i]) {
19398 var dd = this.ids[i][j];
19399 if (! this.isTypeOfDD(dd)) {
19402 if (!bTargetsOnly || dd.isTarget) {
19403 oDDs[oDDs.length] = dd;
19412 * Returns true if the specified dd target is a legal target for
19413 * the specifice drag obj
19414 * @method isLegalTarget
19415 * @param {DragDrop} the drag obj
19416 * @param {DragDrop} the target
19417 * @return {boolean} true if the target is a legal target for the
19421 isLegalTarget: function (oDD, oTargetDD) {
19422 var targets = this.getRelated(oDD, true);
19423 for (var i=0, len=targets.length;i<len;++i) {
19424 if (targets[i].id == oTargetDD.id) {
19433 * My goal is to be able to transparently determine if an object is
19434 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19435 * returns "object", oDD.constructor.toString() always returns
19436 * "DragDrop" and not the name of the subclass. So for now it just
19437 * evaluates a well-known variable in DragDrop.
19438 * @method isTypeOfDD
19439 * @param {Object} the object to evaluate
19440 * @return {boolean} true if typeof oDD = DragDrop
19443 isTypeOfDD: function (oDD) {
19444 return (oDD && oDD.__ygDragDrop);
19448 * Utility function to determine if a given element has been
19449 * registered as a drag drop handle for the given Drag Drop object.
19451 * @param {String} id the element id to check
19452 * @return {boolean} true if this element is a DragDrop handle, false
19456 isHandle: function(sDDId, sHandleId) {
19457 return ( this.handleIds[sDDId] &&
19458 this.handleIds[sDDId][sHandleId] );
19462 * Returns the DragDrop instance for a given id
19463 * @method getDDById
19464 * @param {String} id the id of the DragDrop object
19465 * @return {DragDrop} the drag drop object, null if it is not found
19468 getDDById: function(id) {
19469 for (var i in this.ids) {
19470 if (this.ids[i][id]) {
19471 return this.ids[i][id];
19478 * Fired after a registered DragDrop object gets the mousedown event.
19479 * Sets up the events required to track the object being dragged
19480 * @method handleMouseDown
19481 * @param {Event} e the event
19482 * @param oDD the DragDrop object being dragged
19486 handleMouseDown: function(e, oDD) {
19488 Roo.QuickTips.disable();
19490 this.currentTarget = e.getTarget();
19492 this.dragCurrent = oDD;
19494 var el = oDD.getEl();
19496 // track start position
19497 this.startX = e.getPageX();
19498 this.startY = e.getPageY();
19500 this.deltaX = this.startX - el.offsetLeft;
19501 this.deltaY = this.startY - el.offsetTop;
19503 this.dragThreshMet = false;
19505 this.clickTimeout = setTimeout(
19507 var DDM = Roo.dd.DDM;
19508 DDM.startDrag(DDM.startX, DDM.startY);
19510 this.clickTimeThresh );
19514 * Fired when either the drag pixel threshol or the mousedown hold
19515 * time threshold has been met.
19516 * @method startDrag
19517 * @param x {int} the X position of the original mousedown
19518 * @param y {int} the Y position of the original mousedown
19521 startDrag: function(x, y) {
19522 clearTimeout(this.clickTimeout);
19523 if (this.dragCurrent) {
19524 this.dragCurrent.b4StartDrag(x, y);
19525 this.dragCurrent.startDrag(x, y);
19527 this.dragThreshMet = true;
19531 * Internal function to handle the mouseup event. Will be invoked
19532 * from the context of the document.
19533 * @method handleMouseUp
19534 * @param {Event} e the event
19538 handleMouseUp: function(e) {
19541 Roo.QuickTips.enable();
19543 if (! this.dragCurrent) {
19547 clearTimeout(this.clickTimeout);
19549 if (this.dragThreshMet) {
19550 this.fireEvents(e, true);
19560 * Utility to stop event propagation and event default, if these
19561 * features are turned on.
19562 * @method stopEvent
19563 * @param {Event} e the event as returned by this.getEvent()
19566 stopEvent: function(e){
19567 if(this.stopPropagation) {
19568 e.stopPropagation();
19571 if (this.preventDefault) {
19572 e.preventDefault();
19577 * Internal function to clean up event handlers after the drag
19578 * operation is complete
19580 * @param {Event} e the event
19584 stopDrag: function(e) {
19585 // Fire the drag end event for the item that was dragged
19586 if (this.dragCurrent) {
19587 if (this.dragThreshMet) {
19588 this.dragCurrent.b4EndDrag(e);
19589 this.dragCurrent.endDrag(e);
19592 this.dragCurrent.onMouseUp(e);
19595 this.dragCurrent = null;
19596 this.dragOvers = {};
19600 * Internal function to handle the mousemove event. Will be invoked
19601 * from the context of the html element.
19603 * @TODO figure out what we can do about mouse events lost when the
19604 * user drags objects beyond the window boundary. Currently we can
19605 * detect this in internet explorer by verifying that the mouse is
19606 * down during the mousemove event. Firefox doesn't give us the
19607 * button state on the mousemove event.
19608 * @method handleMouseMove
19609 * @param {Event} e the event
19613 handleMouseMove: function(e) {
19614 if (! this.dragCurrent) {
19618 // var button = e.which || e.button;
19620 // check for IE mouseup outside of page boundary
19621 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19623 return this.handleMouseUp(e);
19626 if (!this.dragThreshMet) {
19627 var diffX = Math.abs(this.startX - e.getPageX());
19628 var diffY = Math.abs(this.startY - e.getPageY());
19629 if (diffX > this.clickPixelThresh ||
19630 diffY > this.clickPixelThresh) {
19631 this.startDrag(this.startX, this.startY);
19635 if (this.dragThreshMet) {
19636 this.dragCurrent.b4Drag(e);
19637 this.dragCurrent.onDrag(e);
19638 if(!this.dragCurrent.moveOnly){
19639 this.fireEvents(e, false);
19649 * Iterates over all of the DragDrop elements to find ones we are
19650 * hovering over or dropping on
19651 * @method fireEvents
19652 * @param {Event} e the event
19653 * @param {boolean} isDrop is this a drop op or a mouseover op?
19657 fireEvents: function(e, isDrop) {
19658 var dc = this.dragCurrent;
19660 // If the user did the mouse up outside of the window, we could
19661 // get here even though we have ended the drag.
19662 if (!dc || dc.isLocked()) {
19666 var pt = e.getPoint();
19668 // cache the previous dragOver array
19674 var enterEvts = [];
19676 // Check to see if the object(s) we were hovering over is no longer
19677 // being hovered over so we can fire the onDragOut event
19678 for (var i in this.dragOvers) {
19680 var ddo = this.dragOvers[i];
19682 if (! this.isTypeOfDD(ddo)) {
19686 if (! this.isOverTarget(pt, ddo, this.mode)) {
19687 outEvts.push( ddo );
19690 oldOvers[i] = true;
19691 delete this.dragOvers[i];
19694 for (var sGroup in dc.groups) {
19696 if ("string" != typeof sGroup) {
19700 for (i in this.ids[sGroup]) {
19701 var oDD = this.ids[sGroup][i];
19702 if (! this.isTypeOfDD(oDD)) {
19706 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19707 if (this.isOverTarget(pt, oDD, this.mode)) {
19708 // look for drop interactions
19710 dropEvts.push( oDD );
19711 // look for drag enter and drag over interactions
19714 // initial drag over: dragEnter fires
19715 if (!oldOvers[oDD.id]) {
19716 enterEvts.push( oDD );
19717 // subsequent drag overs: dragOver fires
19719 overEvts.push( oDD );
19722 this.dragOvers[oDD.id] = oDD;
19730 if (outEvts.length) {
19731 dc.b4DragOut(e, outEvts);
19732 dc.onDragOut(e, outEvts);
19735 if (enterEvts.length) {
19736 dc.onDragEnter(e, enterEvts);
19739 if (overEvts.length) {
19740 dc.b4DragOver(e, overEvts);
19741 dc.onDragOver(e, overEvts);
19744 if (dropEvts.length) {
19745 dc.b4DragDrop(e, dropEvts);
19746 dc.onDragDrop(e, dropEvts);
19750 // fire dragout events
19752 for (i=0, len=outEvts.length; i<len; ++i) {
19753 dc.b4DragOut(e, outEvts[i].id);
19754 dc.onDragOut(e, outEvts[i].id);
19757 // fire enter events
19758 for (i=0,len=enterEvts.length; i<len; ++i) {
19759 // dc.b4DragEnter(e, oDD.id);
19760 dc.onDragEnter(e, enterEvts[i].id);
19763 // fire over events
19764 for (i=0,len=overEvts.length; i<len; ++i) {
19765 dc.b4DragOver(e, overEvts[i].id);
19766 dc.onDragOver(e, overEvts[i].id);
19769 // fire drop events
19770 for (i=0, len=dropEvts.length; i<len; ++i) {
19771 dc.b4DragDrop(e, dropEvts[i].id);
19772 dc.onDragDrop(e, dropEvts[i].id);
19777 // notify about a drop that did not find a target
19778 if (isDrop && !dropEvts.length) {
19779 dc.onInvalidDrop(e);
19785 * Helper function for getting the best match from the list of drag
19786 * and drop objects returned by the drag and drop events when we are
19787 * in INTERSECT mode. It returns either the first object that the
19788 * cursor is over, or the object that has the greatest overlap with
19789 * the dragged element.
19790 * @method getBestMatch
19791 * @param {DragDrop[]} dds The array of drag and drop objects
19793 * @return {DragDrop} The best single match
19796 getBestMatch: function(dds) {
19798 // Return null if the input is not what we expect
19799 //if (!dds || !dds.length || dds.length == 0) {
19801 // If there is only one item, it wins
19802 //} else if (dds.length == 1) {
19804 var len = dds.length;
19809 // Loop through the targeted items
19810 for (var i=0; i<len; ++i) {
19812 // If the cursor is over the object, it wins. If the
19813 // cursor is over multiple matches, the first one we come
19815 if (dd.cursorIsOver) {
19818 // Otherwise the object with the most overlap wins
19821 winner.overlap.getArea() < dd.overlap.getArea()) {
19832 * Refreshes the cache of the top-left and bottom-right points of the
19833 * drag and drop objects in the specified group(s). This is in the
19834 * format that is stored in the drag and drop instance, so typical
19837 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19841 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19843 * @TODO this really should be an indexed array. Alternatively this
19844 * method could accept both.
19845 * @method refreshCache
19846 * @param {Object} groups an associative array of groups to refresh
19849 refreshCache: function(groups) {
19850 for (var sGroup in groups) {
19851 if ("string" != typeof sGroup) {
19854 for (var i in this.ids[sGroup]) {
19855 var oDD = this.ids[sGroup][i];
19857 if (this.isTypeOfDD(oDD)) {
19858 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19859 var loc = this.getLocation(oDD);
19861 this.locationCache[oDD.id] = loc;
19863 delete this.locationCache[oDD.id];
19864 // this will unregister the drag and drop object if
19865 // the element is not in a usable state
19874 * This checks to make sure an element exists and is in the DOM. The
19875 * main purpose is to handle cases where innerHTML is used to remove
19876 * drag and drop objects from the DOM. IE provides an 'unspecified
19877 * error' when trying to access the offsetParent of such an element
19879 * @param {HTMLElement} el the element to check
19880 * @return {boolean} true if the element looks usable
19883 verifyEl: function(el) {
19888 parent = el.offsetParent;
19891 parent = el.offsetParent;
19902 * Returns a Region object containing the drag and drop element's position
19903 * and size, including the padding configured for it
19904 * @method getLocation
19905 * @param {DragDrop} oDD the drag and drop object to get the
19907 * @return {Roo.lib.Region} a Region object representing the total area
19908 * the element occupies, including any padding
19909 * the instance is configured for.
19912 getLocation: function(oDD) {
19913 if (! this.isTypeOfDD(oDD)) {
19917 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
19920 pos= Roo.lib.Dom.getXY(el);
19928 x2 = x1 + el.offsetWidth;
19930 y2 = y1 + el.offsetHeight;
19932 t = y1 - oDD.padding[0];
19933 r = x2 + oDD.padding[1];
19934 b = y2 + oDD.padding[2];
19935 l = x1 - oDD.padding[3];
19937 return new Roo.lib.Region( t, r, b, l );
19941 * Checks the cursor location to see if it over the target
19942 * @method isOverTarget
19943 * @param {Roo.lib.Point} pt The point to evaluate
19944 * @param {DragDrop} oTarget the DragDrop object we are inspecting
19945 * @return {boolean} true if the mouse is over the target
19949 isOverTarget: function(pt, oTarget, intersect) {
19950 // use cache if available
19951 var loc = this.locationCache[oTarget.id];
19952 if (!loc || !this.useCache) {
19953 loc = this.getLocation(oTarget);
19954 this.locationCache[oTarget.id] = loc;
19962 oTarget.cursorIsOver = loc.contains( pt );
19964 // DragDrop is using this as a sanity check for the initial mousedown
19965 // in this case we are done. In POINT mode, if the drag obj has no
19966 // contraints, we are also done. Otherwise we need to evaluate the
19967 // location of the target as related to the actual location of the
19968 // dragged element.
19969 var dc = this.dragCurrent;
19970 if (!dc || !dc.getTargetCoord ||
19971 (!intersect && !dc.constrainX && !dc.constrainY)) {
19972 return oTarget.cursorIsOver;
19975 oTarget.overlap = null;
19977 // Get the current location of the drag element, this is the
19978 // location of the mouse event less the delta that represents
19979 // where the original mousedown happened on the element. We
19980 // need to consider constraints and ticks as well.
19981 var pos = dc.getTargetCoord(pt.x, pt.y);
19983 var el = dc.getDragEl();
19984 var curRegion = new Roo.lib.Region( pos.y,
19985 pos.x + el.offsetWidth,
19986 pos.y + el.offsetHeight,
19989 var overlap = curRegion.intersect(loc);
19992 oTarget.overlap = overlap;
19993 return (intersect) ? true : oTarget.cursorIsOver;
20000 * unload event handler
20001 * @method _onUnload
20005 _onUnload: function(e, me) {
20006 Roo.dd.DragDropMgr.unregAll();
20010 * Cleans up the drag and drop events and objects.
20015 unregAll: function() {
20017 if (this.dragCurrent) {
20019 this.dragCurrent = null;
20022 this._execOnAll("unreg", []);
20024 for (i in this.elementCache) {
20025 delete this.elementCache[i];
20028 this.elementCache = {};
20033 * A cache of DOM elements
20034 * @property elementCache
20041 * Get the wrapper for the DOM element specified
20042 * @method getElWrapper
20043 * @param {String} id the id of the element to get
20044 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20046 * @deprecated This wrapper isn't that useful
20049 getElWrapper: function(id) {
20050 var oWrapper = this.elementCache[id];
20051 if (!oWrapper || !oWrapper.el) {
20052 oWrapper = this.elementCache[id] =
20053 new this.ElementWrapper(Roo.getDom(id));
20059 * Returns the actual DOM element
20060 * @method getElement
20061 * @param {String} id the id of the elment to get
20062 * @return {Object} The element
20063 * @deprecated use Roo.getDom instead
20066 getElement: function(id) {
20067 return Roo.getDom(id);
20071 * Returns the style property for the DOM element (i.e.,
20072 * document.getElById(id).style)
20074 * @param {String} id the id of the elment to get
20075 * @return {Object} The style property of the element
20076 * @deprecated use Roo.getDom instead
20079 getCss: function(id) {
20080 var el = Roo.getDom(id);
20081 return (el) ? el.style : null;
20085 * Inner class for cached elements
20086 * @class DragDropMgr.ElementWrapper
20091 ElementWrapper: function(el) {
20096 this.el = el || null;
20101 this.id = this.el && el.id;
20103 * A reference to the style property
20106 this.css = this.el && el.style;
20110 * Returns the X position of an html element
20112 * @param el the element for which to get the position
20113 * @return {int} the X coordinate
20115 * @deprecated use Roo.lib.Dom.getX instead
20118 getPosX: function(el) {
20119 return Roo.lib.Dom.getX(el);
20123 * Returns the Y position of an html element
20125 * @param el the element for which to get the position
20126 * @return {int} the Y coordinate
20127 * @deprecated use Roo.lib.Dom.getY instead
20130 getPosY: function(el) {
20131 return Roo.lib.Dom.getY(el);
20135 * Swap two nodes. In IE, we use the native method, for others we
20136 * emulate the IE behavior
20138 * @param n1 the first node to swap
20139 * @param n2 the other node to swap
20142 swapNode: function(n1, n2) {
20146 var p = n2.parentNode;
20147 var s = n2.nextSibling;
20150 p.insertBefore(n1, n2);
20151 } else if (n2 == n1.nextSibling) {
20152 p.insertBefore(n2, n1);
20154 n1.parentNode.replaceChild(n2, n1);
20155 p.insertBefore(n1, s);
20161 * Returns the current scroll position
20162 * @method getScroll
20166 getScroll: function () {
20167 var t, l, dde=document.documentElement, db=document.body;
20168 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20170 l = dde.scrollLeft;
20177 return { top: t, left: l };
20181 * Returns the specified element style property
20183 * @param {HTMLElement} el the element
20184 * @param {string} styleProp the style property
20185 * @return {string} The value of the style property
20186 * @deprecated use Roo.lib.Dom.getStyle
20189 getStyle: function(el, styleProp) {
20190 return Roo.fly(el).getStyle(styleProp);
20194 * Gets the scrollTop
20195 * @method getScrollTop
20196 * @return {int} the document's scrollTop
20199 getScrollTop: function () { return this.getScroll().top; },
20202 * Gets the scrollLeft
20203 * @method getScrollLeft
20204 * @return {int} the document's scrollTop
20207 getScrollLeft: function () { return this.getScroll().left; },
20210 * Sets the x/y position of an element to the location of the
20213 * @param {HTMLElement} moveEl The element to move
20214 * @param {HTMLElement} targetEl The position reference element
20217 moveToEl: function (moveEl, targetEl) {
20218 var aCoord = Roo.lib.Dom.getXY(targetEl);
20219 Roo.lib.Dom.setXY(moveEl, aCoord);
20223 * Numeric array sort function
20224 * @method numericSort
20227 numericSort: function(a, b) { return (a - b); },
20231 * @property _timeoutCount
20238 * Trying to make the load order less important. Without this we get
20239 * an error if this file is loaded before the Event Utility.
20240 * @method _addListeners
20244 _addListeners: function() {
20245 var DDM = Roo.dd.DDM;
20246 if ( Roo.lib.Event && document ) {
20249 if (DDM._timeoutCount > 2000) {
20251 setTimeout(DDM._addListeners, 10);
20252 if (document && document.body) {
20253 DDM._timeoutCount += 1;
20260 * Recursively searches the immediate parent and all child nodes for
20261 * the handle element in order to determine wheter or not it was
20263 * @method handleWasClicked
20264 * @param node the html element to inspect
20267 handleWasClicked: function(node, id) {
20268 if (this.isHandle(id, node.id)) {
20271 // check to see if this is a text node child of the one we want
20272 var p = node.parentNode;
20275 if (this.isHandle(id, p.id)) {
20290 // shorter alias, save a few bytes
20291 Roo.dd.DDM = Roo.dd.DragDropMgr;
20292 Roo.dd.DDM._addListeners();
20296 * Ext JS Library 1.1.1
20297 * Copyright(c) 2006-2007, Ext JS, LLC.
20299 * Originally Released Under LGPL - original licence link has changed is not relivant.
20302 * <script type="text/javascript">
20307 * A DragDrop implementation where the linked element follows the
20308 * mouse cursor during a drag.
20309 * @extends Roo.dd.DragDrop
20311 * @param {String} id the id of the linked element
20312 * @param {String} sGroup the group of related DragDrop items
20313 * @param {object} config an object containing configurable attributes
20314 * Valid properties for DD:
20317 Roo.dd.DD = function(id, sGroup, config) {
20319 this.init(id, sGroup, config);
20323 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20326 * When set to true, the utility automatically tries to scroll the browser
20327 * window wehn a drag and drop element is dragged near the viewport boundary.
20328 * Defaults to true.
20335 * Sets the pointer offset to the distance between the linked element's top
20336 * left corner and the location the element was clicked
20337 * @method autoOffset
20338 * @param {int} iPageX the X coordinate of the click
20339 * @param {int} iPageY the Y coordinate of the click
20341 autoOffset: function(iPageX, iPageY) {
20342 var x = iPageX - this.startPageX;
20343 var y = iPageY - this.startPageY;
20344 this.setDelta(x, y);
20348 * Sets the pointer offset. You can call this directly to force the
20349 * offset to be in a particular location (e.g., pass in 0,0 to set it
20350 * to the center of the object)
20352 * @param {int} iDeltaX the distance from the left
20353 * @param {int} iDeltaY the distance from the top
20355 setDelta: function(iDeltaX, iDeltaY) {
20356 this.deltaX = iDeltaX;
20357 this.deltaY = iDeltaY;
20361 * Sets the drag element to the location of the mousedown or click event,
20362 * maintaining the cursor location relative to the location on the element
20363 * that was clicked. Override this if you want to place the element in a
20364 * location other than where the cursor is.
20365 * @method setDragElPos
20366 * @param {int} iPageX the X coordinate of the mousedown or drag event
20367 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20369 setDragElPos: function(iPageX, iPageY) {
20370 // the first time we do this, we are going to check to make sure
20371 // the element has css positioning
20373 var el = this.getDragEl();
20374 this.alignElWithMouse(el, iPageX, iPageY);
20378 * Sets the element to the location of the mousedown or click event,
20379 * maintaining the cursor location relative to the location on the element
20380 * that was clicked. Override this if you want to place the element in a
20381 * location other than where the cursor is.
20382 * @method alignElWithMouse
20383 * @param {HTMLElement} el the element to move
20384 * @param {int} iPageX the X coordinate of the mousedown or drag event
20385 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20387 alignElWithMouse: function(el, iPageX, iPageY) {
20388 var oCoord = this.getTargetCoord(iPageX, iPageY);
20389 var fly = el.dom ? el : Roo.fly(el);
20390 if (!this.deltaSetXY) {
20391 var aCoord = [oCoord.x, oCoord.y];
20393 var newLeft = fly.getLeft(true);
20394 var newTop = fly.getTop(true);
20395 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20397 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20400 this.cachePosition(oCoord.x, oCoord.y);
20401 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20406 * Saves the most recent position so that we can reset the constraints and
20407 * tick marks on-demand. We need to know this so that we can calculate the
20408 * number of pixels the element is offset from its original position.
20409 * @method cachePosition
20410 * @param iPageX the current x position (optional, this just makes it so we
20411 * don't have to look it up again)
20412 * @param iPageY the current y position (optional, this just makes it so we
20413 * don't have to look it up again)
20415 cachePosition: function(iPageX, iPageY) {
20417 this.lastPageX = iPageX;
20418 this.lastPageY = iPageY;
20420 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20421 this.lastPageX = aCoord[0];
20422 this.lastPageY = aCoord[1];
20427 * Auto-scroll the window if the dragged object has been moved beyond the
20428 * visible window boundary.
20429 * @method autoScroll
20430 * @param {int} x the drag element's x position
20431 * @param {int} y the drag element's y position
20432 * @param {int} h the height of the drag element
20433 * @param {int} w the width of the drag element
20436 autoScroll: function(x, y, h, w) {
20439 // The client height
20440 var clientH = Roo.lib.Dom.getViewWidth();
20442 // The client width
20443 var clientW = Roo.lib.Dom.getViewHeight();
20445 // The amt scrolled down
20446 var st = this.DDM.getScrollTop();
20448 // The amt scrolled right
20449 var sl = this.DDM.getScrollLeft();
20451 // Location of the bottom of the element
20454 // Location of the right of the element
20457 // The distance from the cursor to the bottom of the visible area,
20458 // adjusted so that we don't scroll if the cursor is beyond the
20459 // element drag constraints
20460 var toBot = (clientH + st - y - this.deltaY);
20462 // The distance from the cursor to the right of the visible area
20463 var toRight = (clientW + sl - x - this.deltaX);
20466 // How close to the edge the cursor must be before we scroll
20467 // var thresh = (document.all) ? 100 : 40;
20470 // How many pixels to scroll per autoscroll op. This helps to reduce
20471 // clunky scrolling. IE is more sensitive about this ... it needs this
20472 // value to be higher.
20473 var scrAmt = (document.all) ? 80 : 30;
20475 // Scroll down if we are near the bottom of the visible page and the
20476 // obj extends below the crease
20477 if ( bot > clientH && toBot < thresh ) {
20478 window.scrollTo(sl, st + scrAmt);
20481 // Scroll up if the window is scrolled down and the top of the object
20482 // goes above the top border
20483 if ( y < st && st > 0 && y - st < thresh ) {
20484 window.scrollTo(sl, st - scrAmt);
20487 // Scroll right if the obj is beyond the right border and the cursor is
20488 // near the border.
20489 if ( right > clientW && toRight < thresh ) {
20490 window.scrollTo(sl + scrAmt, st);
20493 // Scroll left if the window has been scrolled to the right and the obj
20494 // extends past the left border
20495 if ( x < sl && sl > 0 && x - sl < thresh ) {
20496 window.scrollTo(sl - scrAmt, st);
20502 * Finds the location the element should be placed if we want to move
20503 * it to where the mouse location less the click offset would place us.
20504 * @method getTargetCoord
20505 * @param {int} iPageX the X coordinate of the click
20506 * @param {int} iPageY the Y coordinate of the click
20507 * @return an object that contains the coordinates (Object.x and Object.y)
20510 getTargetCoord: function(iPageX, iPageY) {
20513 var x = iPageX - this.deltaX;
20514 var y = iPageY - this.deltaY;
20516 if (this.constrainX) {
20517 if (x < this.minX) { x = this.minX; }
20518 if (x > this.maxX) { x = this.maxX; }
20521 if (this.constrainY) {
20522 if (y < this.minY) { y = this.minY; }
20523 if (y > this.maxY) { y = this.maxY; }
20526 x = this.getTick(x, this.xTicks);
20527 y = this.getTick(y, this.yTicks);
20534 * Sets up config options specific to this class. Overrides
20535 * Roo.dd.DragDrop, but all versions of this method through the
20536 * inheritance chain are called
20538 applyConfig: function() {
20539 Roo.dd.DD.superclass.applyConfig.call(this);
20540 this.scroll = (this.config.scroll !== false);
20544 * Event that fires prior to the onMouseDown event. Overrides
20547 b4MouseDown: function(e) {
20548 // this.resetConstraints();
20549 this.autoOffset(e.getPageX(),
20554 * Event that fires prior to the onDrag event. Overrides
20557 b4Drag: function(e) {
20558 this.setDragElPos(e.getPageX(),
20562 toString: function() {
20563 return ("DD " + this.id);
20566 //////////////////////////////////////////////////////////////////////////
20567 // Debugging ygDragDrop events that can be overridden
20568 //////////////////////////////////////////////////////////////////////////
20570 startDrag: function(x, y) {
20573 onDrag: function(e) {
20576 onDragEnter: function(e, id) {
20579 onDragOver: function(e, id) {
20582 onDragOut: function(e, id) {
20585 onDragDrop: function(e, id) {
20588 endDrag: function(e) {
20595 * Ext JS Library 1.1.1
20596 * Copyright(c) 2006-2007, Ext JS, LLC.
20598 * Originally Released Under LGPL - original licence link has changed is not relivant.
20601 * <script type="text/javascript">
20605 * @class Roo.dd.DDProxy
20606 * A DragDrop implementation that inserts an empty, bordered div into
20607 * the document that follows the cursor during drag operations. At the time of
20608 * the click, the frame div is resized to the dimensions of the linked html
20609 * element, and moved to the exact location of the linked element.
20611 * References to the "frame" element refer to the single proxy element that
20612 * was created to be dragged in place of all DDProxy elements on the
20615 * @extends Roo.dd.DD
20617 * @param {String} id the id of the linked html element
20618 * @param {String} sGroup the group of related DragDrop objects
20619 * @param {object} config an object containing configurable attributes
20620 * Valid properties for DDProxy in addition to those in DragDrop:
20621 * resizeFrame, centerFrame, dragElId
20623 Roo.dd.DDProxy = function(id, sGroup, config) {
20625 this.init(id, sGroup, config);
20631 * The default drag frame div id
20632 * @property Roo.dd.DDProxy.dragElId
20636 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20638 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20641 * By default we resize the drag frame to be the same size as the element
20642 * we want to drag (this is to get the frame effect). We can turn it off
20643 * if we want a different behavior.
20644 * @property resizeFrame
20650 * By default the frame is positioned exactly where the drag element is, so
20651 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20652 * you do not have constraints on the obj is to have the drag frame centered
20653 * around the cursor. Set centerFrame to true for this effect.
20654 * @property centerFrame
20657 centerFrame: false,
20660 * Creates the proxy element if it does not yet exist
20661 * @method createFrame
20663 createFrame: function() {
20665 var body = document.body;
20667 if (!body || !body.firstChild) {
20668 setTimeout( function() { self.createFrame(); }, 50 );
20672 var div = this.getDragEl();
20675 div = document.createElement("div");
20676 div.id = this.dragElId;
20679 s.position = "absolute";
20680 s.visibility = "hidden";
20682 s.border = "2px solid #aaa";
20685 // appendChild can blow up IE if invoked prior to the window load event
20686 // while rendering a table. It is possible there are other scenarios
20687 // that would cause this to happen as well.
20688 body.insertBefore(div, body.firstChild);
20693 * Initialization for the drag frame element. Must be called in the
20694 * constructor of all subclasses
20695 * @method initFrame
20697 initFrame: function() {
20698 this.createFrame();
20701 applyConfig: function() {
20702 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20704 this.resizeFrame = (this.config.resizeFrame !== false);
20705 this.centerFrame = (this.config.centerFrame);
20706 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20710 * Resizes the drag frame to the dimensions of the clicked object, positions
20711 * it over the object, and finally displays it
20712 * @method showFrame
20713 * @param {int} iPageX X click position
20714 * @param {int} iPageY Y click position
20717 showFrame: function(iPageX, iPageY) {
20718 var el = this.getEl();
20719 var dragEl = this.getDragEl();
20720 var s = dragEl.style;
20722 this._resizeProxy();
20724 if (this.centerFrame) {
20725 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20726 Math.round(parseInt(s.height, 10)/2) );
20729 this.setDragElPos(iPageX, iPageY);
20731 Roo.fly(dragEl).show();
20735 * The proxy is automatically resized to the dimensions of the linked
20736 * element when a drag is initiated, unless resizeFrame is set to false
20737 * @method _resizeProxy
20740 _resizeProxy: function() {
20741 if (this.resizeFrame) {
20742 var el = this.getEl();
20743 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20747 // overrides Roo.dd.DragDrop
20748 b4MouseDown: function(e) {
20749 var x = e.getPageX();
20750 var y = e.getPageY();
20751 this.autoOffset(x, y);
20752 this.setDragElPos(x, y);
20755 // overrides Roo.dd.DragDrop
20756 b4StartDrag: function(x, y) {
20757 // show the drag frame
20758 this.showFrame(x, y);
20761 // overrides Roo.dd.DragDrop
20762 b4EndDrag: function(e) {
20763 Roo.fly(this.getDragEl()).hide();
20766 // overrides Roo.dd.DragDrop
20767 // By default we try to move the element to the last location of the frame.
20768 // This is so that the default behavior mirrors that of Roo.dd.DD.
20769 endDrag: function(e) {
20771 var lel = this.getEl();
20772 var del = this.getDragEl();
20774 // Show the drag frame briefly so we can get its position
20775 del.style.visibility = "";
20778 // Hide the linked element before the move to get around a Safari
20780 lel.style.visibility = "hidden";
20781 Roo.dd.DDM.moveToEl(lel, del);
20782 del.style.visibility = "hidden";
20783 lel.style.visibility = "";
20788 beforeMove : function(){
20792 afterDrag : function(){
20796 toString: function() {
20797 return ("DDProxy " + this.id);
20803 * Ext JS Library 1.1.1
20804 * Copyright(c) 2006-2007, Ext JS, LLC.
20806 * Originally Released Under LGPL - original licence link has changed is not relivant.
20809 * <script type="text/javascript">
20813 * @class Roo.dd.DDTarget
20814 * A DragDrop implementation that does not move, but can be a drop
20815 * target. You would get the same result by simply omitting implementation
20816 * for the event callbacks, but this way we reduce the processing cost of the
20817 * event listener and the callbacks.
20818 * @extends Roo.dd.DragDrop
20820 * @param {String} id the id of the element that is a drop target
20821 * @param {String} sGroup the group of related DragDrop objects
20822 * @param {object} config an object containing configurable attributes
20823 * Valid properties for DDTarget in addition to those in
20827 Roo.dd.DDTarget = function(id, sGroup, config) {
20829 this.initTarget(id, sGroup, config);
20831 if (config.listeners || config.events) {
20832 Roo.dd.DragDrop.superclass.constructor.call(this, {
20833 listeners : config.listeners || {},
20834 events : config.events || {}
20839 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20840 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20841 toString: function() {
20842 return ("DDTarget " + this.id);
20847 * Ext JS Library 1.1.1
20848 * Copyright(c) 2006-2007, Ext JS, LLC.
20850 * Originally Released Under LGPL - original licence link has changed is not relivant.
20853 * <script type="text/javascript">
20858 * @class Roo.dd.ScrollManager
20859 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20860 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20863 Roo.dd.ScrollManager = function(){
20864 var ddm = Roo.dd.DragDropMgr;
20871 var onStop = function(e){
20876 var triggerRefresh = function(){
20877 if(ddm.dragCurrent){
20878 ddm.refreshCache(ddm.dragCurrent.groups);
20882 var doScroll = function(){
20883 if(ddm.dragCurrent){
20884 var dds = Roo.dd.ScrollManager;
20886 if(proc.el.scroll(proc.dir, dds.increment)){
20890 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
20895 var clearProc = function(){
20897 clearInterval(proc.id);
20904 var startProc = function(el, dir){
20905 Roo.log('scroll startproc');
20909 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
20912 var onFire = function(e, isDrop){
20914 if(isDrop || !ddm.dragCurrent){ return; }
20915 var dds = Roo.dd.ScrollManager;
20916 if(!dragEl || dragEl != ddm.dragCurrent){
20917 dragEl = ddm.dragCurrent;
20918 // refresh regions on drag start
20919 dds.refreshCache();
20922 var xy = Roo.lib.Event.getXY(e);
20923 var pt = new Roo.lib.Point(xy[0], xy[1]);
20924 for(var id in els){
20925 var el = els[id], r = el._region;
20926 if(r && r.contains(pt) && el.isScrollable()){
20927 if(r.bottom - pt.y <= dds.thresh){
20929 startProc(el, "down");
20932 }else if(r.right - pt.x <= dds.thresh){
20934 startProc(el, "left");
20937 }else if(pt.y - r.top <= dds.thresh){
20939 startProc(el, "up");
20942 }else if(pt.x - r.left <= dds.thresh){
20944 startProc(el, "right");
20953 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
20954 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
20958 * Registers new overflow element(s) to auto scroll
20959 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
20961 register : function(el){
20962 if(el instanceof Array){
20963 for(var i = 0, len = el.length; i < len; i++) {
20964 this.register(el[i]);
20970 Roo.dd.ScrollManager.els = els;
20974 * Unregisters overflow element(s) so they are no longer scrolled
20975 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
20977 unregister : function(el){
20978 if(el instanceof Array){
20979 for(var i = 0, len = el.length; i < len; i++) {
20980 this.unregister(el[i]);
20989 * The number of pixels from the edge of a container the pointer needs to be to
20990 * trigger scrolling (defaults to 25)
20996 * The number of pixels to scroll in each scroll increment (defaults to 50)
21002 * The frequency of scrolls in milliseconds (defaults to 500)
21008 * True to animate the scroll (defaults to true)
21014 * The animation duration in seconds -
21015 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21021 * Manually trigger a cache refresh.
21023 refreshCache : function(){
21024 for(var id in els){
21025 if(typeof els[id] == 'object'){ // for people extending the object prototype
21026 els[id]._region = els[id].getRegion();
21033 * Ext JS Library 1.1.1
21034 * Copyright(c) 2006-2007, Ext JS, LLC.
21036 * Originally Released Under LGPL - original licence link has changed is not relivant.
21039 * <script type="text/javascript">
21044 * @class Roo.dd.Registry
21045 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21046 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21049 Roo.dd.Registry = function(){
21052 var autoIdSeed = 0;
21054 var getId = function(el, autogen){
21055 if(typeof el == "string"){
21059 if(!id && autogen !== false){
21060 id = "roodd-" + (++autoIdSeed);
21068 * Register a drag drop element
21069 * @param {String|HTMLElement} element The id or DOM node to register
21070 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21071 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21072 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21073 * populated in the data object (if applicable):
21075 Value Description<br />
21076 --------- ------------------------------------------<br />
21077 handles Array of DOM nodes that trigger dragging<br />
21078 for the element being registered<br />
21079 isHandle True if the element passed in triggers<br />
21080 dragging itself, else false
21083 register : function(el, data){
21085 if(typeof el == "string"){
21086 el = document.getElementById(el);
21089 elements[getId(el)] = data;
21090 if(data.isHandle !== false){
21091 handles[data.ddel.id] = data;
21094 var hs = data.handles;
21095 for(var i = 0, len = hs.length; i < len; i++){
21096 handles[getId(hs[i])] = data;
21102 * Unregister a drag drop element
21103 * @param {String|HTMLElement} element The id or DOM node to unregister
21105 unregister : function(el){
21106 var id = getId(el, false);
21107 var data = elements[id];
21109 delete elements[id];
21111 var hs = data.handles;
21112 for(var i = 0, len = hs.length; i < len; i++){
21113 delete handles[getId(hs[i], false)];
21120 * Returns the handle registered for a DOM Node by id
21121 * @param {String|HTMLElement} id The DOM node or id to look up
21122 * @return {Object} handle The custom handle data
21124 getHandle : function(id){
21125 if(typeof id != "string"){ // must be element?
21128 return handles[id];
21132 * Returns the handle that is registered for the DOM node that is the target of the event
21133 * @param {Event} e The event
21134 * @return {Object} handle The custom handle data
21136 getHandleFromEvent : function(e){
21137 var t = Roo.lib.Event.getTarget(e);
21138 return t ? handles[t.id] : null;
21142 * Returns a custom data object that is registered for a DOM node by id
21143 * @param {String|HTMLElement} id The DOM node or id to look up
21144 * @return {Object} data The custom data
21146 getTarget : function(id){
21147 if(typeof id != "string"){ // must be element?
21150 return elements[id];
21154 * Returns a custom data object that is registered for the DOM node that is the target of the event
21155 * @param {Event} e The event
21156 * @return {Object} data The custom data
21158 getTargetFromEvent : function(e){
21159 var t = Roo.lib.Event.getTarget(e);
21160 return t ? elements[t.id] || handles[t.id] : null;
21165 * Ext JS Library 1.1.1
21166 * Copyright(c) 2006-2007, Ext JS, LLC.
21168 * Originally Released Under LGPL - original licence link has changed is not relivant.
21171 * <script type="text/javascript">
21176 * @class Roo.dd.StatusProxy
21177 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21178 * default drag proxy used by all Roo.dd components.
21180 * @param {Object} config
21182 Roo.dd.StatusProxy = function(config){
21183 Roo.apply(this, config);
21184 this.id = this.id || Roo.id();
21185 this.el = new Roo.Layer({
21187 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21188 {tag: "div", cls: "x-dd-drop-icon"},
21189 {tag: "div", cls: "x-dd-drag-ghost"}
21192 shadow: !config || config.shadow !== false
21194 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21195 this.dropStatus = this.dropNotAllowed;
21198 Roo.dd.StatusProxy.prototype = {
21200 * @cfg {String} dropAllowed
21201 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21203 dropAllowed : "x-dd-drop-ok",
21205 * @cfg {String} dropNotAllowed
21206 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21208 dropNotAllowed : "x-dd-drop-nodrop",
21211 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21212 * over the current target element.
21213 * @param {String} cssClass The css class for the new drop status indicator image
21215 setStatus : function(cssClass){
21216 cssClass = cssClass || this.dropNotAllowed;
21217 if(this.dropStatus != cssClass){
21218 this.el.replaceClass(this.dropStatus, cssClass);
21219 this.dropStatus = cssClass;
21224 * Resets the status indicator to the default dropNotAllowed value
21225 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21227 reset : function(clearGhost){
21228 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21229 this.dropStatus = this.dropNotAllowed;
21231 this.ghost.update("");
21236 * Updates the contents of the ghost element
21237 * @param {String} html The html that will replace the current innerHTML of the ghost element
21239 update : function(html){
21240 if(typeof html == "string"){
21241 this.ghost.update(html);
21243 this.ghost.update("");
21244 html.style.margin = "0";
21245 this.ghost.dom.appendChild(html);
21247 // ensure float = none set?? cant remember why though.
21248 var el = this.ghost.dom.firstChild;
21250 Roo.fly(el).setStyle('float', 'none');
21255 * Returns the underlying proxy {@link Roo.Layer}
21256 * @return {Roo.Layer} el
21258 getEl : function(){
21263 * Returns the ghost element
21264 * @return {Roo.Element} el
21266 getGhost : function(){
21272 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21274 hide : function(clear){
21282 * Stops the repair animation if it's currently running
21285 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21291 * Displays this proxy
21298 * Force the Layer to sync its shadow and shim positions to the element
21305 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21306 * invalid drop operation by the item being dragged.
21307 * @param {Array} xy The XY position of the element ([x, y])
21308 * @param {Function} callback The function to call after the repair is complete
21309 * @param {Object} scope The scope in which to execute the callback
21311 repair : function(xy, callback, scope){
21312 this.callback = callback;
21313 this.scope = scope;
21314 if(xy && this.animRepair !== false){
21315 this.el.addClass("x-dd-drag-repair");
21316 this.el.hideUnders(true);
21317 this.anim = this.el.shift({
21318 duration: this.repairDuration || .5,
21322 callback: this.afterRepair,
21326 this.afterRepair();
21331 afterRepair : function(){
21333 if(typeof this.callback == "function"){
21334 this.callback.call(this.scope || this);
21336 this.callback = null;
21341 * Ext JS Library 1.1.1
21342 * Copyright(c) 2006-2007, Ext JS, LLC.
21344 * Originally Released Under LGPL - original licence link has changed is not relivant.
21347 * <script type="text/javascript">
21351 * @class Roo.dd.DragSource
21352 * @extends Roo.dd.DDProxy
21353 * A simple class that provides the basic implementation needed to make any element draggable.
21355 * @param {String/HTMLElement/Element} el The container element
21356 * @param {Object} config
21358 Roo.dd.DragSource = function(el, config){
21359 this.el = Roo.get(el);
21360 this.dragData = {};
21362 Roo.apply(this, config);
21365 this.proxy = new Roo.dd.StatusProxy();
21368 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21369 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21371 this.dragging = false;
21374 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21376 * @cfg {String} dropAllowed
21377 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21379 dropAllowed : "x-dd-drop-ok",
21381 * @cfg {String} dropNotAllowed
21382 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21384 dropNotAllowed : "x-dd-drop-nodrop",
21387 * Returns the data object associated with this drag source
21388 * @return {Object} data An object containing arbitrary data
21390 getDragData : function(e){
21391 return this.dragData;
21395 onDragEnter : function(e, id){
21396 var target = Roo.dd.DragDropMgr.getDDById(id);
21397 this.cachedTarget = target;
21398 if(this.beforeDragEnter(target, e, id) !== false){
21399 if(target.isNotifyTarget){
21400 var status = target.notifyEnter(this, e, this.dragData);
21401 this.proxy.setStatus(status);
21403 this.proxy.setStatus(this.dropAllowed);
21406 if(this.afterDragEnter){
21408 * An empty function by default, but provided so that you can perform a custom action
21409 * when the dragged item enters the drop target by providing an implementation.
21410 * @param {Roo.dd.DragDrop} target The drop target
21411 * @param {Event} e The event object
21412 * @param {String} id The id of the dragged element
21413 * @method afterDragEnter
21415 this.afterDragEnter(target, e, id);
21421 * An empty function by default, but provided so that you can perform a custom action
21422 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21423 * @param {Roo.dd.DragDrop} target The drop target
21424 * @param {Event} e The event object
21425 * @param {String} id The id of the dragged element
21426 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21428 beforeDragEnter : function(target, e, id){
21433 alignElWithMouse: function() {
21434 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21439 onDragOver : function(e, id){
21440 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21441 if(this.beforeDragOver(target, e, id) !== false){
21442 if(target.isNotifyTarget){
21443 var status = target.notifyOver(this, e, this.dragData);
21444 this.proxy.setStatus(status);
21447 if(this.afterDragOver){
21449 * An empty function by default, but provided so that you can perform a custom action
21450 * while the dragged item is over the drop target by providing an implementation.
21451 * @param {Roo.dd.DragDrop} target The drop target
21452 * @param {Event} e The event object
21453 * @param {String} id The id of the dragged element
21454 * @method afterDragOver
21456 this.afterDragOver(target, e, id);
21462 * An empty function by default, but provided so that you can perform a custom action
21463 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21464 * @param {Roo.dd.DragDrop} target The drop target
21465 * @param {Event} e The event object
21466 * @param {String} id The id of the dragged element
21467 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21469 beforeDragOver : function(target, e, id){
21474 onDragOut : function(e, id){
21475 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21476 if(this.beforeDragOut(target, e, id) !== false){
21477 if(target.isNotifyTarget){
21478 target.notifyOut(this, e, this.dragData);
21480 this.proxy.reset();
21481 if(this.afterDragOut){
21483 * An empty function by default, but provided so that you can perform a custom action
21484 * after the dragged item is dragged out of the target without dropping.
21485 * @param {Roo.dd.DragDrop} target The drop target
21486 * @param {Event} e The event object
21487 * @param {String} id The id of the dragged element
21488 * @method afterDragOut
21490 this.afterDragOut(target, e, id);
21493 this.cachedTarget = null;
21497 * An empty function by default, but provided so that you can perform a custom action before the dragged
21498 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21499 * @param {Roo.dd.DragDrop} target The drop target
21500 * @param {Event} e The event object
21501 * @param {String} id The id of the dragged element
21502 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21504 beforeDragOut : function(target, e, id){
21509 onDragDrop : function(e, id){
21510 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21511 if(this.beforeDragDrop(target, e, id) !== false){
21512 if(target.isNotifyTarget){
21513 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21514 this.onValidDrop(target, e, id);
21516 this.onInvalidDrop(target, e, id);
21519 this.onValidDrop(target, e, id);
21522 if(this.afterDragDrop){
21524 * An empty function by default, but provided so that you can perform a custom action
21525 * after a valid drag drop has occurred by providing an implementation.
21526 * @param {Roo.dd.DragDrop} target The drop target
21527 * @param {Event} e The event object
21528 * @param {String} id The id of the dropped element
21529 * @method afterDragDrop
21531 this.afterDragDrop(target, e, id);
21534 delete this.cachedTarget;
21538 * An empty function by default, but provided so that you can perform a custom action before the dragged
21539 * item is dropped onto the target and optionally cancel the onDragDrop.
21540 * @param {Roo.dd.DragDrop} target The drop target
21541 * @param {Event} e The event object
21542 * @param {String} id The id of the dragged element
21543 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21545 beforeDragDrop : function(target, e, id){
21550 onValidDrop : function(target, e, id){
21552 if(this.afterValidDrop){
21554 * An empty function by default, but provided so that you can perform a custom action
21555 * after a valid drop has occurred by providing an implementation.
21556 * @param {Object} target The target DD
21557 * @param {Event} e The event object
21558 * @param {String} id The id of the dropped element
21559 * @method afterInvalidDrop
21561 this.afterValidDrop(target, e, id);
21566 getRepairXY : function(e, data){
21567 return this.el.getXY();
21571 onInvalidDrop : function(target, e, id){
21572 this.beforeInvalidDrop(target, e, id);
21573 if(this.cachedTarget){
21574 if(this.cachedTarget.isNotifyTarget){
21575 this.cachedTarget.notifyOut(this, e, this.dragData);
21577 this.cacheTarget = null;
21579 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21581 if(this.afterInvalidDrop){
21583 * An empty function by default, but provided so that you can perform a custom action
21584 * after an invalid drop has occurred by providing an implementation.
21585 * @param {Event} e The event object
21586 * @param {String} id The id of the dropped element
21587 * @method afterInvalidDrop
21589 this.afterInvalidDrop(e, id);
21594 afterRepair : function(){
21596 this.el.highlight(this.hlColor || "c3daf9");
21598 this.dragging = false;
21602 * An empty function by default, but provided so that you can perform a custom action after an invalid
21603 * drop has occurred.
21604 * @param {Roo.dd.DragDrop} target The drop target
21605 * @param {Event} e The event object
21606 * @param {String} id The id of the dragged element
21607 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21609 beforeInvalidDrop : function(target, e, id){
21614 handleMouseDown : function(e){
21615 if(this.dragging) {
21618 var data = this.getDragData(e);
21619 if(data && this.onBeforeDrag(data, e) !== false){
21620 this.dragData = data;
21622 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21627 * An empty function by default, but provided so that you can perform a custom action before the initial
21628 * drag event begins and optionally cancel it.
21629 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21630 * @param {Event} e The event object
21631 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21633 onBeforeDrag : function(data, e){
21638 * An empty function by default, but provided so that you can perform a custom action once the initial
21639 * drag event has begun. The drag cannot be canceled from this function.
21640 * @param {Number} x The x position of the click on the dragged object
21641 * @param {Number} y The y position of the click on the dragged object
21643 onStartDrag : Roo.emptyFn,
21645 // private - YUI override
21646 startDrag : function(x, y){
21647 this.proxy.reset();
21648 this.dragging = true;
21649 this.proxy.update("");
21650 this.onInitDrag(x, y);
21655 onInitDrag : function(x, y){
21656 var clone = this.el.dom.cloneNode(true);
21657 clone.id = Roo.id(); // prevent duplicate ids
21658 this.proxy.update(clone);
21659 this.onStartDrag(x, y);
21664 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21665 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21667 getProxy : function(){
21672 * Hides the drag source's {@link Roo.dd.StatusProxy}
21674 hideProxy : function(){
21676 this.proxy.reset(true);
21677 this.dragging = false;
21681 triggerCacheRefresh : function(){
21682 Roo.dd.DDM.refreshCache(this.groups);
21685 // private - override to prevent hiding
21686 b4EndDrag: function(e) {
21689 // private - override to prevent moving
21690 endDrag : function(e){
21691 this.onEndDrag(this.dragData, e);
21695 onEndDrag : function(data, e){
21698 // private - pin to cursor
21699 autoOffset : function(x, y) {
21700 this.setDelta(-12, -20);
21704 * Ext JS Library 1.1.1
21705 * Copyright(c) 2006-2007, Ext JS, LLC.
21707 * Originally Released Under LGPL - original licence link has changed is not relivant.
21710 * <script type="text/javascript">
21715 * @class Roo.dd.DropTarget
21716 * @extends Roo.dd.DDTarget
21717 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21718 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21720 * @param {String/HTMLElement/Element} el The container element
21721 * @param {Object} config
21723 Roo.dd.DropTarget = function(el, config){
21724 this.el = Roo.get(el);
21726 var listeners = false; ;
21727 if (config && config.listeners) {
21728 listeners= config.listeners;
21729 delete config.listeners;
21731 Roo.apply(this, config);
21733 if(this.containerScroll){
21734 Roo.dd.ScrollManager.register(this.el);
21738 * @scope Roo.dd.DropTarget
21743 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21744 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21745 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21747 * IMPORTANT : it should set this.overClass and this.dropAllowed
21749 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21750 * @param {Event} e The event
21751 * @param {Object} data An object containing arbitrary data supplied by the drag source
21757 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21758 * This method will be called on every mouse movement while the drag source is over the drop target.
21759 * This default implementation simply returns the dropAllowed config value.
21761 * IMPORTANT : it should set this.dropAllowed
21763 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21764 * @param {Event} e The event
21765 * @param {Object} data An object containing arbitrary data supplied by the drag source
21771 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21772 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21773 * overClass (if any) from the drop element.
21775 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21776 * @param {Event} e The event
21777 * @param {Object} data An object containing arbitrary data supplied by the drag source
21783 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21784 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21785 * implementation that does something to process the drop event and returns true so that the drag source's
21786 * repair action does not run.
21788 * IMPORTANT : it should set this.success
21790 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21791 * @param {Event} e The event
21792 * @param {Object} data An object containing arbitrary data supplied by the drag source
21798 Roo.dd.DropTarget.superclass.constructor.call( this,
21800 this.ddGroup || this.group,
21803 listeners : listeners || {}
21811 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21813 * @cfg {String} overClass
21814 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21817 * @cfg {String} ddGroup
21818 * The drag drop group to handle drop events for
21822 * @cfg {String} dropAllowed
21823 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21825 dropAllowed : "x-dd-drop-ok",
21827 * @cfg {String} dropNotAllowed
21828 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21830 dropNotAllowed : "x-dd-drop-nodrop",
21832 * @cfg {boolean} success
21833 * set this after drop listener..
21837 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21838 * if the drop point is valid for over/enter..
21845 isNotifyTarget : true,
21850 notifyEnter : function(dd, e, data)
21853 this.fireEvent('enter', dd, e, data);
21854 if(this.overClass){
21855 this.el.addClass(this.overClass);
21857 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21858 this.valid ? this.dropAllowed : this.dropNotAllowed
21865 notifyOver : function(dd, e, data)
21868 this.fireEvent('over', dd, e, data);
21869 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21870 this.valid ? this.dropAllowed : this.dropNotAllowed
21877 notifyOut : function(dd, e, data)
21879 this.fireEvent('out', dd, e, data);
21880 if(this.overClass){
21881 this.el.removeClass(this.overClass);
21888 notifyDrop : function(dd, e, data)
21890 this.success = false;
21891 this.fireEvent('drop', dd, e, data);
21892 return this.success;
21896 * Ext JS Library 1.1.1
21897 * Copyright(c) 2006-2007, Ext JS, LLC.
21899 * Originally Released Under LGPL - original licence link has changed is not relivant.
21902 * <script type="text/javascript">
21907 * @class Roo.dd.DragZone
21908 * @extends Roo.dd.DragSource
21909 * This class provides a container DD instance that proxies for multiple child node sources.<br />
21910 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
21912 * @param {String/HTMLElement/Element} el The container element
21913 * @param {Object} config
21915 Roo.dd.DragZone = function(el, config){
21916 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
21917 if(this.containerScroll){
21918 Roo.dd.ScrollManager.register(this.el);
21922 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
21924 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
21925 * for auto scrolling during drag operations.
21928 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
21929 * method after a failed drop (defaults to "c3daf9" - light blue)
21933 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
21934 * for a valid target to drag based on the mouse down. Override this method
21935 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
21936 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
21937 * @param {EventObject} e The mouse down event
21938 * @return {Object} The dragData
21940 getDragData : function(e){
21941 return Roo.dd.Registry.getHandleFromEvent(e);
21945 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
21946 * this.dragData.ddel
21947 * @param {Number} x The x position of the click on the dragged object
21948 * @param {Number} y The y position of the click on the dragged object
21949 * @return {Boolean} true to continue the drag, false to cancel
21951 onInitDrag : function(x, y){
21952 this.proxy.update(this.dragData.ddel.cloneNode(true));
21953 this.onStartDrag(x, y);
21958 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
21960 afterRepair : function(){
21962 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
21964 this.dragging = false;
21968 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
21969 * the XY of this.dragData.ddel
21970 * @param {EventObject} e The mouse up event
21971 * @return {Array} The xy location (e.g. [100, 200])
21973 getRepairXY : function(e){
21974 return Roo.Element.fly(this.dragData.ddel).getXY();
21978 * Ext JS Library 1.1.1
21979 * Copyright(c) 2006-2007, Ext JS, LLC.
21981 * Originally Released Under LGPL - original licence link has changed is not relivant.
21984 * <script type="text/javascript">
21987 * @class Roo.dd.DropZone
21988 * @extends Roo.dd.DropTarget
21989 * This class provides a container DD instance that proxies for multiple child node targets.<br />
21990 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
21992 * @param {String/HTMLElement/Element} el The container element
21993 * @param {Object} config
21995 Roo.dd.DropZone = function(el, config){
21996 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
21999 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22001 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22002 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22003 * provide your own custom lookup.
22004 * @param {Event} e The event
22005 * @return {Object} data The custom data
22007 getTargetFromEvent : function(e){
22008 return Roo.dd.Registry.getTargetFromEvent(e);
22012 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22013 * that it has registered. This method has no default implementation and should be overridden to provide
22014 * node-specific processing if necessary.
22015 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22016 * {@link #getTargetFromEvent} for this node)
22017 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22018 * @param {Event} e The event
22019 * @param {Object} data An object containing arbitrary data supplied by the drag source
22021 onNodeEnter : function(n, dd, e, data){
22026 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22027 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22028 * overridden to provide the proper feedback.
22029 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22030 * {@link #getTargetFromEvent} for this node)
22031 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22032 * @param {Event} e The event
22033 * @param {Object} data An object containing arbitrary data supplied by the drag source
22034 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22035 * underlying {@link Roo.dd.StatusProxy} can be updated
22037 onNodeOver : function(n, dd, e, data){
22038 return this.dropAllowed;
22042 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22043 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22044 * node-specific processing if necessary.
22045 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22046 * {@link #getTargetFromEvent} for this node)
22047 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22048 * @param {Event} e The event
22049 * @param {Object} data An object containing arbitrary data supplied by the drag source
22051 onNodeOut : function(n, dd, e, data){
22056 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22057 * the drop node. The default implementation returns false, so it should be overridden to provide the
22058 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22059 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22060 * {@link #getTargetFromEvent} for this node)
22061 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22062 * @param {Event} e The event
22063 * @param {Object} data An object containing arbitrary data supplied by the drag source
22064 * @return {Boolean} True if the drop was valid, else false
22066 onNodeDrop : function(n, dd, e, data){
22071 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22072 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22073 * it should be overridden to provide the proper feedback if necessary.
22074 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22075 * @param {Event} e The event
22076 * @param {Object} data An object containing arbitrary data supplied by the drag source
22077 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22078 * underlying {@link Roo.dd.StatusProxy} can be updated
22080 onContainerOver : function(dd, e, data){
22081 return this.dropNotAllowed;
22085 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22086 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22087 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22088 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22089 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22090 * @param {Event} e The event
22091 * @param {Object} data An object containing arbitrary data supplied by the drag source
22092 * @return {Boolean} True if the drop was valid, else false
22094 onContainerDrop : function(dd, e, data){
22099 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22100 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22101 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22102 * you should override this method and provide a custom implementation.
22103 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22104 * @param {Event} e The event
22105 * @param {Object} data An object containing arbitrary data supplied by the drag source
22106 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22107 * underlying {@link Roo.dd.StatusProxy} can be updated
22109 notifyEnter : function(dd, e, data){
22110 return this.dropNotAllowed;
22114 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22115 * This method will be called on every mouse movement while the drag source is over the drop zone.
22116 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22117 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22118 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22119 * registered node, it will call {@link #onContainerOver}.
22120 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22121 * @param {Event} e The event
22122 * @param {Object} data An object containing arbitrary data supplied by the drag source
22123 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22124 * underlying {@link Roo.dd.StatusProxy} can be updated
22126 notifyOver : function(dd, e, data){
22127 var n = this.getTargetFromEvent(e);
22128 if(!n){ // not over valid drop target
22129 if(this.lastOverNode){
22130 this.onNodeOut(this.lastOverNode, dd, e, data);
22131 this.lastOverNode = null;
22133 return this.onContainerOver(dd, e, data);
22135 if(this.lastOverNode != n){
22136 if(this.lastOverNode){
22137 this.onNodeOut(this.lastOverNode, dd, e, data);
22139 this.onNodeEnter(n, dd, e, data);
22140 this.lastOverNode = n;
22142 return this.onNodeOver(n, dd, e, data);
22146 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22147 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22148 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22149 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22150 * @param {Event} e The event
22151 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22153 notifyOut : function(dd, e, data){
22154 if(this.lastOverNode){
22155 this.onNodeOut(this.lastOverNode, dd, e, data);
22156 this.lastOverNode = null;
22161 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22162 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22163 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22164 * otherwise it will call {@link #onContainerDrop}.
22165 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22166 * @param {Event} e The event
22167 * @param {Object} data An object containing arbitrary data supplied by the drag source
22168 * @return {Boolean} True if the drop was valid, else false
22170 notifyDrop : function(dd, e, data){
22171 if(this.lastOverNode){
22172 this.onNodeOut(this.lastOverNode, dd, e, data);
22173 this.lastOverNode = null;
22175 var n = this.getTargetFromEvent(e);
22177 this.onNodeDrop(n, dd, e, data) :
22178 this.onContainerDrop(dd, e, data);
22182 triggerCacheRefresh : function(){
22183 Roo.dd.DDM.refreshCache(this.groups);
22187 * Ext JS Library 1.1.1
22188 * Copyright(c) 2006-2007, Ext JS, LLC.
22190 * Originally Released Under LGPL - original licence link has changed is not relivant.
22193 * <script type="text/javascript">
22198 * @class Roo.data.SortTypes
22200 * Defines the default sorting (casting?) comparison functions used when sorting data.
22202 Roo.data.SortTypes = {
22204 * Default sort that does nothing
22205 * @param {Mixed} s The value being converted
22206 * @return {Mixed} The comparison value
22208 none : function(s){
22213 * The regular expression used to strip tags
22217 stripTagsRE : /<\/?[^>]+>/gi,
22220 * Strips all HTML tags to sort on text only
22221 * @param {Mixed} s The value being converted
22222 * @return {String} The comparison value
22224 asText : function(s){
22225 return String(s).replace(this.stripTagsRE, "");
22229 * Strips all HTML tags to sort on text only - Case insensitive
22230 * @param {Mixed} s The value being converted
22231 * @return {String} The comparison value
22233 asUCText : function(s){
22234 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22238 * Case insensitive string
22239 * @param {Mixed} s The value being converted
22240 * @return {String} The comparison value
22242 asUCString : function(s) {
22243 return String(s).toUpperCase();
22248 * @param {Mixed} s The value being converted
22249 * @return {Number} The comparison value
22251 asDate : function(s) {
22255 if(s instanceof Date){
22256 return s.getTime();
22258 return Date.parse(String(s));
22263 * @param {Mixed} s The value being converted
22264 * @return {Float} The comparison value
22266 asFloat : function(s) {
22267 var val = parseFloat(String(s).replace(/,/g, ""));
22276 * @param {Mixed} s The value being converted
22277 * @return {Number} The comparison value
22279 asInt : function(s) {
22280 var val = parseInt(String(s).replace(/,/g, ""));
22288 * Ext JS Library 1.1.1
22289 * Copyright(c) 2006-2007, Ext JS, LLC.
22291 * Originally Released Under LGPL - original licence link has changed is not relivant.
22294 * <script type="text/javascript">
22298 * @class Roo.data.Record
22299 * Instances of this class encapsulate both record <em>definition</em> information, and record
22300 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22301 * to access Records cached in an {@link Roo.data.Store} object.<br>
22303 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22304 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22307 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22309 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22310 * {@link #create}. The parameters are the same.
22311 * @param {Array} data An associative Array of data values keyed by the field name.
22312 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22313 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22314 * not specified an integer id is generated.
22316 Roo.data.Record = function(data, id){
22317 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22322 * Generate a constructor for a specific record layout.
22323 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22324 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22325 * Each field definition object may contain the following properties: <ul>
22326 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
22327 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22328 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22329 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22330 * is being used, then this is a string containing the javascript expression to reference the data relative to
22331 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22332 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22333 * this may be omitted.</p></li>
22334 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22335 * <ul><li>auto (Default, implies no conversion)</li>
22340 * <li>date</li></ul></p></li>
22341 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22342 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22343 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22344 * by the Reader into an object that will be stored in the Record. It is passed the
22345 * following parameters:<ul>
22346 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22348 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22350 * <br>usage:<br><pre><code>
22351 var TopicRecord = Roo.data.Record.create(
22352 {name: 'title', mapping: 'topic_title'},
22353 {name: 'author', mapping: 'username'},
22354 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22355 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22356 {name: 'lastPoster', mapping: 'user2'},
22357 {name: 'excerpt', mapping: 'post_text'}
22360 var myNewRecord = new TopicRecord({
22361 title: 'Do my job please',
22364 lastPost: new Date(),
22365 lastPoster: 'Animal',
22366 excerpt: 'No way dude!'
22368 myStore.add(myNewRecord);
22373 Roo.data.Record.create = function(o){
22374 var f = function(){
22375 f.superclass.constructor.apply(this, arguments);
22377 Roo.extend(f, Roo.data.Record);
22378 var p = f.prototype;
22379 p.fields = new Roo.util.MixedCollection(false, function(field){
22382 for(var i = 0, len = o.length; i < len; i++){
22383 p.fields.add(new Roo.data.Field(o[i]));
22385 f.getField = function(name){
22386 return p.fields.get(name);
22391 Roo.data.Record.AUTO_ID = 1000;
22392 Roo.data.Record.EDIT = 'edit';
22393 Roo.data.Record.REJECT = 'reject';
22394 Roo.data.Record.COMMIT = 'commit';
22396 Roo.data.Record.prototype = {
22398 * Readonly flag - true if this record has been modified.
22407 join : function(store){
22408 this.store = store;
22412 * Set the named field to the specified value.
22413 * @param {String} name The name of the field to set.
22414 * @param {Object} value The value to set the field to.
22416 set : function(name, value){
22417 if(this.data[name] == value){
22421 if(!this.modified){
22422 this.modified = {};
22424 if(typeof this.modified[name] == 'undefined'){
22425 this.modified[name] = this.data[name];
22427 this.data[name] = value;
22428 if(!this.editing && this.store){
22429 this.store.afterEdit(this);
22434 * Get the value of the named field.
22435 * @param {String} name The name of the field to get the value of.
22436 * @return {Object} The value of the field.
22438 get : function(name){
22439 return this.data[name];
22443 beginEdit : function(){
22444 this.editing = true;
22445 this.modified = {};
22449 cancelEdit : function(){
22450 this.editing = false;
22451 delete this.modified;
22455 endEdit : function(){
22456 this.editing = false;
22457 if(this.dirty && this.store){
22458 this.store.afterEdit(this);
22463 * Usually called by the {@link Roo.data.Store} which owns the Record.
22464 * Rejects all changes made to the Record since either creation, or the last commit operation.
22465 * Modified fields are reverted to their original values.
22467 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22468 * of reject operations.
22470 reject : function(){
22471 var m = this.modified;
22473 if(typeof m[n] != "function"){
22474 this.data[n] = m[n];
22477 this.dirty = false;
22478 delete this.modified;
22479 this.editing = false;
22481 this.store.afterReject(this);
22486 * Usually called by the {@link Roo.data.Store} which owns the Record.
22487 * Commits all changes made to the Record since either creation, or the last commit operation.
22489 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22490 * of commit operations.
22492 commit : function(){
22493 this.dirty = false;
22494 delete this.modified;
22495 this.editing = false;
22497 this.store.afterCommit(this);
22502 hasError : function(){
22503 return this.error != null;
22507 clearError : function(){
22512 * Creates a copy of this record.
22513 * @param {String} id (optional) A new record id if you don't want to use this record's id
22516 copy : function(newId) {
22517 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22521 * Ext JS Library 1.1.1
22522 * Copyright(c) 2006-2007, Ext JS, LLC.
22524 * Originally Released Under LGPL - original licence link has changed is not relivant.
22527 * <script type="text/javascript">
22533 * @class Roo.data.Store
22534 * @extends Roo.util.Observable
22535 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22536 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22538 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
22539 * has no knowledge of the format of the data returned by the Proxy.<br>
22541 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22542 * instances from the data object. These records are cached and made available through accessor functions.
22544 * Creates a new Store.
22545 * @param {Object} config A config object containing the objects needed for the Store to access data,
22546 * and read the data into Records.
22548 Roo.data.Store = function(config){
22549 this.data = new Roo.util.MixedCollection(false);
22550 this.data.getKey = function(o){
22553 this.baseParams = {};
22555 this.paramNames = {
22560 "multisort" : "_multisort"
22563 if(config && config.data){
22564 this.inlineData = config.data;
22565 delete config.data;
22568 Roo.apply(this, config);
22570 if(this.reader){ // reader passed
22571 this.reader = Roo.factory(this.reader, Roo.data);
22572 this.reader.xmodule = this.xmodule || false;
22573 if(!this.recordType){
22574 this.recordType = this.reader.recordType;
22576 if(this.reader.onMetaChange){
22577 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22581 if(this.recordType){
22582 this.fields = this.recordType.prototype.fields;
22584 this.modified = [];
22588 * @event datachanged
22589 * Fires when the data cache has changed, and a widget which is using this Store
22590 * as a Record cache should refresh its view.
22591 * @param {Store} this
22593 datachanged : true,
22595 * @event metachange
22596 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22597 * @param {Store} this
22598 * @param {Object} meta The JSON metadata
22603 * Fires when Records have been added to the Store
22604 * @param {Store} this
22605 * @param {Roo.data.Record[]} records The array of Records added
22606 * @param {Number} index The index at which the record(s) were added
22611 * Fires when a Record has been removed from the Store
22612 * @param {Store} this
22613 * @param {Roo.data.Record} record The Record that was removed
22614 * @param {Number} index The index at which the record was removed
22619 * Fires when a Record has been updated
22620 * @param {Store} this
22621 * @param {Roo.data.Record} record The Record that was updated
22622 * @param {String} operation The update operation being performed. Value may be one of:
22624 Roo.data.Record.EDIT
22625 Roo.data.Record.REJECT
22626 Roo.data.Record.COMMIT
22632 * Fires when the data cache has been cleared.
22633 * @param {Store} this
22637 * @event beforeload
22638 * Fires before a request is made for a new data object. If the beforeload handler returns false
22639 * the load action will be canceled.
22640 * @param {Store} this
22641 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22645 * @event beforeloadadd
22646 * Fires after a new set of Records has been loaded.
22647 * @param {Store} this
22648 * @param {Roo.data.Record[]} records The Records that were loaded
22649 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22651 beforeloadadd : true,
22654 * Fires after a new set of Records has been loaded, before they are added to the store.
22655 * @param {Store} this
22656 * @param {Roo.data.Record[]} records The Records that were loaded
22657 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22658 * @params {Object} return from reader
22662 * @event loadexception
22663 * Fires if an exception occurs in the Proxy during loading.
22664 * Called with the signature of the Proxy's "loadexception" event.
22665 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22668 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22669 * @param {Object} load options
22670 * @param {Object} jsonData from your request (normally this contains the Exception)
22672 loadexception : true
22676 this.proxy = Roo.factory(this.proxy, Roo.data);
22677 this.proxy.xmodule = this.xmodule || false;
22678 this.relayEvents(this.proxy, ["loadexception"]);
22680 this.sortToggle = {};
22681 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22683 Roo.data.Store.superclass.constructor.call(this);
22685 if(this.inlineData){
22686 this.loadData(this.inlineData);
22687 delete this.inlineData;
22691 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22693 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22694 * without a remote query - used by combo/forms at present.
22698 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22701 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22704 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22705 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22708 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22709 * on any HTTP request
22712 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22715 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22719 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22720 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22722 remoteSort : false,
22725 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22726 * loaded or when a record is removed. (defaults to false).
22728 pruneModifiedRecords : false,
22731 lastOptions : null,
22734 * Add Records to the Store and fires the add event.
22735 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22737 add : function(records){
22738 records = [].concat(records);
22739 for(var i = 0, len = records.length; i < len; i++){
22740 records[i].join(this);
22742 var index = this.data.length;
22743 this.data.addAll(records);
22744 this.fireEvent("add", this, records, index);
22748 * Remove a Record from the Store and fires the remove event.
22749 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22751 remove : function(record){
22752 var index = this.data.indexOf(record);
22753 this.data.removeAt(index);
22754 if(this.pruneModifiedRecords){
22755 this.modified.remove(record);
22757 this.fireEvent("remove", this, record, index);
22761 * Remove all Records from the Store and fires the clear event.
22763 removeAll : function(){
22765 if(this.pruneModifiedRecords){
22766 this.modified = [];
22768 this.fireEvent("clear", this);
22772 * Inserts Records to the Store at the given index and fires the add event.
22773 * @param {Number} index The start index at which to insert the passed Records.
22774 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22776 insert : function(index, records){
22777 records = [].concat(records);
22778 for(var i = 0, len = records.length; i < len; i++){
22779 this.data.insert(index, records[i]);
22780 records[i].join(this);
22782 this.fireEvent("add", this, records, index);
22786 * Get the index within the cache of the passed Record.
22787 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22788 * @return {Number} The index of the passed Record. Returns -1 if not found.
22790 indexOf : function(record){
22791 return this.data.indexOf(record);
22795 * Get the index within the cache of the Record with the passed id.
22796 * @param {String} id The id of the Record to find.
22797 * @return {Number} The index of the Record. Returns -1 if not found.
22799 indexOfId : function(id){
22800 return this.data.indexOfKey(id);
22804 * Get the Record with the specified id.
22805 * @param {String} id The id of the Record to find.
22806 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22808 getById : function(id){
22809 return this.data.key(id);
22813 * Get the Record at the specified index.
22814 * @param {Number} index The index of the Record to find.
22815 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22817 getAt : function(index){
22818 return this.data.itemAt(index);
22822 * Returns a range of Records between specified indices.
22823 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22824 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22825 * @return {Roo.data.Record[]} An array of Records
22827 getRange : function(start, end){
22828 return this.data.getRange(start, end);
22832 storeOptions : function(o){
22833 o = Roo.apply({}, o);
22836 this.lastOptions = o;
22840 * Loads the Record cache from the configured Proxy using the configured Reader.
22842 * If using remote paging, then the first load call must specify the <em>start</em>
22843 * and <em>limit</em> properties in the options.params property to establish the initial
22844 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22846 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22847 * and this call will return before the new data has been loaded. Perform any post-processing
22848 * in a callback function, or in a "load" event handler.</strong>
22850 * @param {Object} options An object containing properties which control loading options:<ul>
22851 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22852 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22853 * passed the following arguments:<ul>
22854 * <li>r : Roo.data.Record[]</li>
22855 * <li>options: Options object from the load call</li>
22856 * <li>success: Boolean success indicator</li></ul></li>
22857 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22858 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
22861 load : function(options){
22862 options = options || {};
22863 if(this.fireEvent("beforeload", this, options) !== false){
22864 this.storeOptions(options);
22865 var p = Roo.apply(options.params || {}, this.baseParams);
22866 // if meta was not loaded from remote source.. try requesting it.
22867 if (!this.reader.metaFromRemote) {
22868 p._requestMeta = 1;
22870 if(this.sortInfo && this.remoteSort){
22871 var pn = this.paramNames;
22872 p[pn["sort"]] = this.sortInfo.field;
22873 p[pn["dir"]] = this.sortInfo.direction;
22875 if (this.multiSort) {
22876 var pn = this.paramNames;
22877 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
22880 this.proxy.load(p, this.reader, this.loadRecords, this, options);
22885 * Reloads the Record cache from the configured Proxy using the configured Reader and
22886 * the options from the last load operation performed.
22887 * @param {Object} options (optional) An object containing properties which may override the options
22888 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
22889 * the most recently used options are reused).
22891 reload : function(options){
22892 this.load(Roo.applyIf(options||{}, this.lastOptions));
22896 // Called as a callback by the Reader during a load operation.
22897 loadRecords : function(o, options, success){
22898 if(!o || success === false){
22899 if(success !== false){
22900 this.fireEvent("load", this, [], options, o);
22902 if(options.callback){
22903 options.callback.call(options.scope || this, [], options, false);
22907 // if data returned failure - throw an exception.
22908 if (o.success === false) {
22909 // show a message if no listener is registered.
22910 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
22911 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
22913 // loadmask wil be hooked into this..
22914 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
22917 var r = o.records, t = o.totalRecords || r.length;
22919 this.fireEvent("beforeloadadd", this, r, options, o);
22921 if(!options || options.add !== true){
22922 if(this.pruneModifiedRecords){
22923 this.modified = [];
22925 for(var i = 0, len = r.length; i < len; i++){
22929 this.data = this.snapshot;
22930 delete this.snapshot;
22933 this.data.addAll(r);
22934 this.totalLength = t;
22936 this.fireEvent("datachanged", this);
22938 this.totalLength = Math.max(t, this.data.length+r.length);
22941 this.fireEvent("load", this, r, options, o);
22942 if(options.callback){
22943 options.callback.call(options.scope || this, r, options, true);
22949 * Loads data from a passed data block. A Reader which understands the format of the data
22950 * must have been configured in the constructor.
22951 * @param {Object} data The data block from which to read the Records. The format of the data expected
22952 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
22953 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
22955 loadData : function(o, append){
22956 var r = this.reader.readRecords(o);
22957 this.loadRecords(r, {add: append}, true);
22961 * Gets the number of cached records.
22963 * <em>If using paging, this may not be the total size of the dataset. If the data object
22964 * used by the Reader contains the dataset size, then the getTotalCount() function returns
22965 * the data set size</em>
22967 getCount : function(){
22968 return this.data.length || 0;
22972 * Gets the total number of records in the dataset as returned by the server.
22974 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
22975 * the dataset size</em>
22977 getTotalCount : function(){
22978 return this.totalLength || 0;
22982 * Returns the sort state of the Store as an object with two properties:
22984 field {String} The name of the field by which the Records are sorted
22985 direction {String} The sort order, "ASC" or "DESC"
22988 getSortState : function(){
22989 return this.sortInfo;
22993 applySort : function(){
22994 if(this.sortInfo && !this.remoteSort){
22995 var s = this.sortInfo, f = s.field;
22996 var st = this.fields.get(f).sortType;
22997 var fn = function(r1, r2){
22998 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
22999 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23001 this.data.sort(s.direction, fn);
23002 if(this.snapshot && this.snapshot != this.data){
23003 this.snapshot.sort(s.direction, fn);
23009 * Sets the default sort column and order to be used by the next load operation.
23010 * @param {String} fieldName The name of the field to sort by.
23011 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23013 setDefaultSort : function(field, dir){
23014 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23018 * Sort the Records.
23019 * If remote sorting is used, the sort is performed on the server, and the cache is
23020 * reloaded. If local sorting is used, the cache is sorted internally.
23021 * @param {String} fieldName The name of the field to sort by.
23022 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23024 sort : function(fieldName, dir){
23025 var f = this.fields.get(fieldName);
23027 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23029 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23030 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23035 this.sortToggle[f.name] = dir;
23036 this.sortInfo = {field: f.name, direction: dir};
23037 if(!this.remoteSort){
23039 this.fireEvent("datachanged", this);
23041 this.load(this.lastOptions);
23046 * Calls the specified function for each of the Records in the cache.
23047 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23048 * Returning <em>false</em> aborts and exits the iteration.
23049 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23051 each : function(fn, scope){
23052 this.data.each(fn, scope);
23056 * Gets all records modified since the last commit. Modified records are persisted across load operations
23057 * (e.g., during paging).
23058 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23060 getModifiedRecords : function(){
23061 return this.modified;
23065 createFilterFn : function(property, value, anyMatch){
23066 if(!value.exec){ // not a regex
23067 value = String(value);
23068 if(value.length == 0){
23071 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23073 return function(r){
23074 return value.test(r.data[property]);
23079 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23080 * @param {String} property A field on your records
23081 * @param {Number} start The record index to start at (defaults to 0)
23082 * @param {Number} end The last record index to include (defaults to length - 1)
23083 * @return {Number} The sum
23085 sum : function(property, start, end){
23086 var rs = this.data.items, v = 0;
23087 start = start || 0;
23088 end = (end || end === 0) ? end : rs.length-1;
23090 for(var i = start; i <= end; i++){
23091 v += (rs[i].data[property] || 0);
23097 * Filter the records by a specified property.
23098 * @param {String} field A field on your records
23099 * @param {String/RegExp} value Either a string that the field
23100 * should start with or a RegExp to test against the field
23101 * @param {Boolean} anyMatch True to match any part not just the beginning
23103 filter : function(property, value, anyMatch){
23104 var fn = this.createFilterFn(property, value, anyMatch);
23105 return fn ? this.filterBy(fn) : this.clearFilter();
23109 * Filter by a function. The specified function will be called with each
23110 * record in this data source. If the function returns true the record is included,
23111 * otherwise it is filtered.
23112 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23113 * @param {Object} scope (optional) The scope of the function (defaults to this)
23115 filterBy : function(fn, scope){
23116 this.snapshot = this.snapshot || this.data;
23117 this.data = this.queryBy(fn, scope||this);
23118 this.fireEvent("datachanged", this);
23122 * Query the records by a specified property.
23123 * @param {String} field A field on your records
23124 * @param {String/RegExp} value Either a string that the field
23125 * should start with or a RegExp to test against the field
23126 * @param {Boolean} anyMatch True to match any part not just the beginning
23127 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23129 query : function(property, value, anyMatch){
23130 var fn = this.createFilterFn(property, value, anyMatch);
23131 return fn ? this.queryBy(fn) : this.data.clone();
23135 * Query by a function. The specified function will be called with each
23136 * record in this data source. If the function returns true the record is included
23138 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23139 * @param {Object} scope (optional) The scope of the function (defaults to this)
23140 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23142 queryBy : function(fn, scope){
23143 var data = this.snapshot || this.data;
23144 return data.filterBy(fn, scope||this);
23148 * Collects unique values for a particular dataIndex from this store.
23149 * @param {String} dataIndex The property to collect
23150 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23151 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23152 * @return {Array} An array of the unique values
23154 collect : function(dataIndex, allowNull, bypassFilter){
23155 var d = (bypassFilter === true && this.snapshot) ?
23156 this.snapshot.items : this.data.items;
23157 var v, sv, r = [], l = {};
23158 for(var i = 0, len = d.length; i < len; i++){
23159 v = d[i].data[dataIndex];
23161 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23170 * Revert to a view of the Record cache with no filtering applied.
23171 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23173 clearFilter : function(suppressEvent){
23174 if(this.snapshot && this.snapshot != this.data){
23175 this.data = this.snapshot;
23176 delete this.snapshot;
23177 if(suppressEvent !== true){
23178 this.fireEvent("datachanged", this);
23184 afterEdit : function(record){
23185 if(this.modified.indexOf(record) == -1){
23186 this.modified.push(record);
23188 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23192 afterReject : function(record){
23193 this.modified.remove(record);
23194 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23198 afterCommit : function(record){
23199 this.modified.remove(record);
23200 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23204 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23205 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23207 commitChanges : function(){
23208 var m = this.modified.slice(0);
23209 this.modified = [];
23210 for(var i = 0, len = m.length; i < len; i++){
23216 * Cancel outstanding changes on all changed records.
23218 rejectChanges : function(){
23219 var m = this.modified.slice(0);
23220 this.modified = [];
23221 for(var i = 0, len = m.length; i < len; i++){
23226 onMetaChange : function(meta, rtype, o){
23227 this.recordType = rtype;
23228 this.fields = rtype.prototype.fields;
23229 delete this.snapshot;
23230 this.sortInfo = meta.sortInfo || this.sortInfo;
23231 this.modified = [];
23232 this.fireEvent('metachange', this, this.reader.meta);
23235 moveIndex : function(data, type)
23237 var index = this.indexOf(data);
23239 var newIndex = index + type;
23243 this.insert(newIndex, data);
23248 * Ext JS Library 1.1.1
23249 * Copyright(c) 2006-2007, Ext JS, LLC.
23251 * Originally Released Under LGPL - original licence link has changed is not relivant.
23254 * <script type="text/javascript">
23258 * @class Roo.data.SimpleStore
23259 * @extends Roo.data.Store
23260 * Small helper class to make creating Stores from Array data easier.
23261 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23262 * @cfg {Array} fields An array of field definition objects, or field name strings.
23263 * @cfg {Array} data The multi-dimensional array of data
23265 * @param {Object} config
23267 Roo.data.SimpleStore = function(config){
23268 Roo.data.SimpleStore.superclass.constructor.call(this, {
23270 reader: new Roo.data.ArrayReader({
23273 Roo.data.Record.create(config.fields)
23275 proxy : new Roo.data.MemoryProxy(config.data)
23279 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23281 * Ext JS Library 1.1.1
23282 * Copyright(c) 2006-2007, Ext JS, LLC.
23284 * Originally Released Under LGPL - original licence link has changed is not relivant.
23287 * <script type="text/javascript">
23292 * @extends Roo.data.Store
23293 * @class Roo.data.JsonStore
23294 * Small helper class to make creating Stores for JSON data easier. <br/>
23296 var store = new Roo.data.JsonStore({
23297 url: 'get-images.php',
23299 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23302 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23303 * JsonReader and HttpProxy (unless inline data is provided).</b>
23304 * @cfg {Array} fields An array of field definition objects, or field name strings.
23306 * @param {Object} config
23308 Roo.data.JsonStore = function(c){
23309 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23310 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23311 reader: new Roo.data.JsonReader(c, c.fields)
23314 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23316 * Ext JS Library 1.1.1
23317 * Copyright(c) 2006-2007, Ext JS, LLC.
23319 * Originally Released Under LGPL - original licence link has changed is not relivant.
23322 * <script type="text/javascript">
23326 Roo.data.Field = function(config){
23327 if(typeof config == "string"){
23328 config = {name: config};
23330 Roo.apply(this, config);
23333 this.type = "auto";
23336 var st = Roo.data.SortTypes;
23337 // named sortTypes are supported, here we look them up
23338 if(typeof this.sortType == "string"){
23339 this.sortType = st[this.sortType];
23342 // set default sortType for strings and dates
23343 if(!this.sortType){
23346 this.sortType = st.asUCString;
23349 this.sortType = st.asDate;
23352 this.sortType = st.none;
23357 var stripRe = /[\$,%]/g;
23359 // prebuilt conversion function for this field, instead of
23360 // switching every time we're reading a value
23362 var cv, dateFormat = this.dateFormat;
23367 cv = function(v){ return v; };
23370 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23374 return v !== undefined && v !== null && v !== '' ?
23375 parseInt(String(v).replace(stripRe, ""), 10) : '';
23380 return v !== undefined && v !== null && v !== '' ?
23381 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23386 cv = function(v){ return v === true || v === "true" || v == 1; };
23393 if(v instanceof Date){
23397 if(dateFormat == "timestamp"){
23398 return new Date(v*1000);
23400 return Date.parseDate(v, dateFormat);
23402 var parsed = Date.parse(v);
23403 return parsed ? new Date(parsed) : null;
23412 Roo.data.Field.prototype = {
23420 * Ext JS Library 1.1.1
23421 * Copyright(c) 2006-2007, Ext JS, LLC.
23423 * Originally Released Under LGPL - original licence link has changed is not relivant.
23426 * <script type="text/javascript">
23429 // Base class for reading structured data from a data source. This class is intended to be
23430 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23433 * @class Roo.data.DataReader
23434 * Base class for reading structured data from a data source. This class is intended to be
23435 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23438 Roo.data.DataReader = function(meta, recordType){
23442 this.recordType = recordType instanceof Array ?
23443 Roo.data.Record.create(recordType) : recordType;
23446 Roo.data.DataReader.prototype = {
23448 * Create an empty record
23449 * @param {Object} data (optional) - overlay some values
23450 * @return {Roo.data.Record} record created.
23452 newRow : function(d) {
23454 this.recordType.prototype.fields.each(function(c) {
23456 case 'int' : da[c.name] = 0; break;
23457 case 'date' : da[c.name] = new Date(); break;
23458 case 'float' : da[c.name] = 0.0; break;
23459 case 'boolean' : da[c.name] = false; break;
23460 default : da[c.name] = ""; break;
23464 return new this.recordType(Roo.apply(da, d));
23469 * Ext JS Library 1.1.1
23470 * Copyright(c) 2006-2007, Ext JS, LLC.
23472 * Originally Released Under LGPL - original licence link has changed is not relivant.
23475 * <script type="text/javascript">
23479 * @class Roo.data.DataProxy
23480 * @extends Roo.data.Observable
23481 * This class is an abstract base class for implementations which provide retrieval of
23482 * unformatted data objects.<br>
23484 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23485 * (of the appropriate type which knows how to parse the data object) to provide a block of
23486 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23488 * Custom implementations must implement the load method as described in
23489 * {@link Roo.data.HttpProxy#load}.
23491 Roo.data.DataProxy = function(){
23494 * @event beforeload
23495 * Fires before a network request is made to retrieve a data object.
23496 * @param {Object} This DataProxy object.
23497 * @param {Object} params The params parameter to the load function.
23502 * Fires before the load method's callback is called.
23503 * @param {Object} This DataProxy object.
23504 * @param {Object} o The data object.
23505 * @param {Object} arg The callback argument object passed to the load function.
23509 * @event loadexception
23510 * Fires if an Exception occurs during data retrieval.
23511 * @param {Object} This DataProxy object.
23512 * @param {Object} o The data object.
23513 * @param {Object} arg The callback argument object passed to the load function.
23514 * @param {Object} e The Exception.
23516 loadexception : true
23518 Roo.data.DataProxy.superclass.constructor.call(this);
23521 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23524 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23528 * Ext JS Library 1.1.1
23529 * Copyright(c) 2006-2007, Ext JS, LLC.
23531 * Originally Released Under LGPL - original licence link has changed is not relivant.
23534 * <script type="text/javascript">
23537 * @class Roo.data.MemoryProxy
23538 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23539 * to the Reader when its load method is called.
23541 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23543 Roo.data.MemoryProxy = function(data){
23547 Roo.data.MemoryProxy.superclass.constructor.call(this);
23551 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23553 * Load data from the requested source (in this case an in-memory
23554 * data object passed to the constructor), read the data object into
23555 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23556 * process that block using the passed callback.
23557 * @param {Object} params This parameter is not used by the MemoryProxy class.
23558 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23559 * object into a block of Roo.data.Records.
23560 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23561 * The function must be passed <ul>
23562 * <li>The Record block object</li>
23563 * <li>The "arg" argument from the load function</li>
23564 * <li>A boolean success indicator</li>
23566 * @param {Object} scope The scope in which to call the callback
23567 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23569 load : function(params, reader, callback, scope, arg){
23570 params = params || {};
23573 result = reader.readRecords(this.data);
23575 this.fireEvent("loadexception", this, arg, null, e);
23576 callback.call(scope, null, arg, false);
23579 callback.call(scope, result, arg, true);
23583 update : function(params, records){
23588 * Ext JS Library 1.1.1
23589 * Copyright(c) 2006-2007, Ext JS, LLC.
23591 * Originally Released Under LGPL - original licence link has changed is not relivant.
23594 * <script type="text/javascript">
23597 * @class Roo.data.HttpProxy
23598 * @extends Roo.data.DataProxy
23599 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23600 * configured to reference a certain URL.<br><br>
23602 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23603 * from which the running page was served.<br><br>
23605 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23607 * Be aware that to enable the browser to parse an XML document, the server must set
23608 * the Content-Type header in the HTTP response to "text/xml".
23610 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23611 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23612 * will be used to make the request.
23614 Roo.data.HttpProxy = function(conn){
23615 Roo.data.HttpProxy.superclass.constructor.call(this);
23616 // is conn a conn config or a real conn?
23618 this.useAjax = !conn || !conn.events;
23622 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23623 // thse are take from connection...
23626 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23629 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23630 * extra parameters to each request made by this object. (defaults to undefined)
23633 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23634 * to each request made by this object. (defaults to undefined)
23637 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
23640 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23643 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23649 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23653 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23654 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23655 * a finer-grained basis than the DataProxy events.
23657 getConnection : function(){
23658 return this.useAjax ? Roo.Ajax : this.conn;
23662 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23663 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23664 * process that block using the passed callback.
23665 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23666 * for the request to the remote server.
23667 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23668 * object into a block of Roo.data.Records.
23669 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23670 * The function must be passed <ul>
23671 * <li>The Record block object</li>
23672 * <li>The "arg" argument from the load function</li>
23673 * <li>A boolean success indicator</li>
23675 * @param {Object} scope The scope in which to call the callback
23676 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23678 load : function(params, reader, callback, scope, arg){
23679 if(this.fireEvent("beforeload", this, params) !== false){
23681 params : params || {},
23683 callback : callback,
23688 callback : this.loadResponse,
23692 Roo.applyIf(o, this.conn);
23693 if(this.activeRequest){
23694 Roo.Ajax.abort(this.activeRequest);
23696 this.activeRequest = Roo.Ajax.request(o);
23698 this.conn.request(o);
23701 callback.call(scope||this, null, arg, false);
23706 loadResponse : function(o, success, response){
23707 delete this.activeRequest;
23709 this.fireEvent("loadexception", this, o, response);
23710 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23715 result = o.reader.read(response);
23717 this.fireEvent("loadexception", this, o, response, e);
23718 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23722 this.fireEvent("load", this, o, o.request.arg);
23723 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23727 update : function(dataSet){
23732 updateResponse : function(dataSet){
23737 * Ext JS Library 1.1.1
23738 * Copyright(c) 2006-2007, Ext JS, LLC.
23740 * Originally Released Under LGPL - original licence link has changed is not relivant.
23743 * <script type="text/javascript">
23747 * @class Roo.data.ScriptTagProxy
23748 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23749 * other than the originating domain of the running page.<br><br>
23751 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
23752 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23754 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23755 * source code that is used as the source inside a <script> tag.<br><br>
23757 * In order for the browser to process the returned data, the server must wrap the data object
23758 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23759 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23760 * depending on whether the callback name was passed:
23763 boolean scriptTag = false;
23764 String cb = request.getParameter("callback");
23767 response.setContentType("text/javascript");
23769 response.setContentType("application/x-json");
23771 Writer out = response.getWriter();
23773 out.write(cb + "(");
23775 out.print(dataBlock.toJsonString());
23782 * @param {Object} config A configuration object.
23784 Roo.data.ScriptTagProxy = function(config){
23785 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23786 Roo.apply(this, config);
23787 this.head = document.getElementsByTagName("head")[0];
23790 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23792 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23794 * @cfg {String} url The URL from which to request the data object.
23797 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23801 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23802 * the server the name of the callback function set up by the load call to process the returned data object.
23803 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23804 * javascript output which calls this named function passing the data object as its only parameter.
23806 callbackParam : "callback",
23808 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23809 * name to the request.
23814 * Load data from the configured URL, read the data object into
23815 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23816 * process that block using the passed callback.
23817 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23818 * for the request to the remote server.
23819 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23820 * object into a block of Roo.data.Records.
23821 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23822 * The function must be passed <ul>
23823 * <li>The Record block object</li>
23824 * <li>The "arg" argument from the load function</li>
23825 * <li>A boolean success indicator</li>
23827 * @param {Object} scope The scope in which to call the callback
23828 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23830 load : function(params, reader, callback, scope, arg){
23831 if(this.fireEvent("beforeload", this, params) !== false){
23833 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23835 var url = this.url;
23836 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23838 url += "&_dc=" + (new Date().getTime());
23840 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23843 cb : "stcCallback"+transId,
23844 scriptId : "stcScript"+transId,
23848 callback : callback,
23854 window[trans.cb] = function(o){
23855 conn.handleResponse(o, trans);
23858 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
23860 if(this.autoAbort !== false){
23864 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
23866 var script = document.createElement("script");
23867 script.setAttribute("src", url);
23868 script.setAttribute("type", "text/javascript");
23869 script.setAttribute("id", trans.scriptId);
23870 this.head.appendChild(script);
23872 this.trans = trans;
23874 callback.call(scope||this, null, arg, false);
23879 isLoading : function(){
23880 return this.trans ? true : false;
23884 * Abort the current server request.
23886 abort : function(){
23887 if(this.isLoading()){
23888 this.destroyTrans(this.trans);
23893 destroyTrans : function(trans, isLoaded){
23894 this.head.removeChild(document.getElementById(trans.scriptId));
23895 clearTimeout(trans.timeoutId);
23897 window[trans.cb] = undefined;
23899 delete window[trans.cb];
23902 // if hasn't been loaded, wait for load to remove it to prevent script error
23903 window[trans.cb] = function(){
23904 window[trans.cb] = undefined;
23906 delete window[trans.cb];
23913 handleResponse : function(o, trans){
23914 this.trans = false;
23915 this.destroyTrans(trans, true);
23918 result = trans.reader.readRecords(o);
23920 this.fireEvent("loadexception", this, o, trans.arg, e);
23921 trans.callback.call(trans.scope||window, null, trans.arg, false);
23924 this.fireEvent("load", this, o, trans.arg);
23925 trans.callback.call(trans.scope||window, result, trans.arg, true);
23929 handleFailure : function(trans){
23930 this.trans = false;
23931 this.destroyTrans(trans, false);
23932 this.fireEvent("loadexception", this, null, trans.arg);
23933 trans.callback.call(trans.scope||window, null, trans.arg, false);
23937 * Ext JS Library 1.1.1
23938 * Copyright(c) 2006-2007, Ext JS, LLC.
23940 * Originally Released Under LGPL - original licence link has changed is not relivant.
23943 * <script type="text/javascript">
23947 * @class Roo.data.JsonReader
23948 * @extends Roo.data.DataReader
23949 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
23950 * based on mappings in a provided Roo.data.Record constructor.
23952 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
23953 * in the reply previously.
23958 var RecordDef = Roo.data.Record.create([
23959 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
23960 {name: 'occupation'} // This field will use "occupation" as the mapping.
23962 var myReader = new Roo.data.JsonReader({
23963 totalProperty: "results", // The property which contains the total dataset size (optional)
23964 root: "rows", // The property which contains an Array of row objects
23965 id: "id" // The property within each row object that provides an ID for the record (optional)
23969 * This would consume a JSON file like this:
23971 { 'results': 2, 'rows': [
23972 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
23973 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
23976 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
23977 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
23978 * paged from the remote server.
23979 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
23980 * @cfg {String} root name of the property which contains the Array of row objects.
23981 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
23982 * @cfg {Array} fields Array of field definition objects
23984 * Create a new JsonReader
23985 * @param {Object} meta Metadata configuration options
23986 * @param {Object} recordType Either an Array of field definition objects,
23987 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
23989 Roo.data.JsonReader = function(meta, recordType){
23992 // set some defaults:
23993 Roo.applyIf(meta, {
23994 totalProperty: 'total',
23995 successProperty : 'success',
24000 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24002 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24005 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24006 * Used by Store query builder to append _requestMeta to params.
24009 metaFromRemote : false,
24011 * This method is only used by a DataProxy which has retrieved data from a remote server.
24012 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24013 * @return {Object} data A data block which is used by an Roo.data.Store object as
24014 * a cache of Roo.data.Records.
24016 read : function(response){
24017 var json = response.responseText;
24019 var o = /* eval:var:o */ eval("("+json+")");
24021 throw {message: "JsonReader.read: Json object not found"};
24027 this.metaFromRemote = true;
24028 this.meta = o.metaData;
24029 this.recordType = Roo.data.Record.create(o.metaData.fields);
24030 this.onMetaChange(this.meta, this.recordType, o);
24032 return this.readRecords(o);
24035 // private function a store will implement
24036 onMetaChange : function(meta, recordType, o){
24043 simpleAccess: function(obj, subsc) {
24050 getJsonAccessor: function(){
24052 return function(expr) {
24054 return(re.test(expr))
24055 ? new Function("obj", "return obj." + expr)
24060 return Roo.emptyFn;
24065 * Create a data block containing Roo.data.Records from an XML document.
24066 * @param {Object} o An object which contains an Array of row objects in the property specified
24067 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24068 * which contains the total size of the dataset.
24069 * @return {Object} data A data block which is used by an Roo.data.Store object as
24070 * a cache of Roo.data.Records.
24072 readRecords : function(o){
24074 * After any data loads, the raw JSON data is available for further custom processing.
24078 var s = this.meta, Record = this.recordType,
24079 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24081 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24083 if(s.totalProperty) {
24084 this.getTotal = this.getJsonAccessor(s.totalProperty);
24086 if(s.successProperty) {
24087 this.getSuccess = this.getJsonAccessor(s.successProperty);
24089 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24091 var g = this.getJsonAccessor(s.id);
24092 this.getId = function(rec) {
24094 return (r === undefined || r === "") ? null : r;
24097 this.getId = function(){return null;};
24100 for(var jj = 0; jj < fl; jj++){
24102 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24103 this.ef[jj] = this.getJsonAccessor(map);
24107 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24108 if(s.totalProperty){
24109 var vt = parseInt(this.getTotal(o), 10);
24114 if(s.successProperty){
24115 var vs = this.getSuccess(o);
24116 if(vs === false || vs === 'false'){
24121 for(var i = 0; i < c; i++){
24124 var id = this.getId(n);
24125 for(var j = 0; j < fl; j++){
24127 var v = this.ef[j](n);
24129 Roo.log('missing convert for ' + f.name);
24133 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24135 var record = new Record(values, id);
24137 records[i] = record;
24143 totalRecords : totalRecords
24148 * Ext JS Library 1.1.1
24149 * Copyright(c) 2006-2007, Ext JS, LLC.
24151 * Originally Released Under LGPL - original licence link has changed is not relivant.
24154 * <script type="text/javascript">
24158 * @class Roo.data.XmlReader
24159 * @extends Roo.data.DataReader
24160 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24161 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24163 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24164 * header in the HTTP response must be set to "text/xml".</em>
24168 var RecordDef = Roo.data.Record.create([
24169 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24170 {name: 'occupation'} // This field will use "occupation" as the mapping.
24172 var myReader = new Roo.data.XmlReader({
24173 totalRecords: "results", // The element which contains the total dataset size (optional)
24174 record: "row", // The repeated element which contains row information
24175 id: "id" // The element within the row that provides an ID for the record (optional)
24179 * This would consume an XML file like this:
24183 <results>2</results>
24186 <name>Bill</name>
24187 <occupation>Gardener</occupation>
24191 <name>Ben</name>
24192 <occupation>Horticulturalist</occupation>
24196 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24197 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24198 * paged from the remote server.
24199 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24200 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24201 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24202 * a record identifier value.
24204 * Create a new XmlReader
24205 * @param {Object} meta Metadata configuration options
24206 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24207 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24208 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24210 Roo.data.XmlReader = function(meta, recordType){
24212 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24214 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24216 * This method is only used by a DataProxy which has retrieved data from a remote server.
24217 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24218 * to contain a method called 'responseXML' that returns an XML document object.
24219 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24220 * a cache of Roo.data.Records.
24222 read : function(response){
24223 var doc = response.responseXML;
24225 throw {message: "XmlReader.read: XML Document not available"};
24227 return this.readRecords(doc);
24231 * Create a data block containing Roo.data.Records from an XML document.
24232 * @param {Object} doc A parsed XML document.
24233 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24234 * a cache of Roo.data.Records.
24236 readRecords : function(doc){
24238 * After any data loads/reads, the raw XML Document is available for further custom processing.
24239 * @type XMLDocument
24241 this.xmlData = doc;
24242 var root = doc.documentElement || doc;
24243 var q = Roo.DomQuery;
24244 var recordType = this.recordType, fields = recordType.prototype.fields;
24245 var sid = this.meta.id;
24246 var totalRecords = 0, success = true;
24247 if(this.meta.totalRecords){
24248 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24251 if(this.meta.success){
24252 var sv = q.selectValue(this.meta.success, root, true);
24253 success = sv !== false && sv !== 'false';
24256 var ns = q.select(this.meta.record, root);
24257 for(var i = 0, len = ns.length; i < len; i++) {
24260 var id = sid ? q.selectValue(sid, n) : undefined;
24261 for(var j = 0, jlen = fields.length; j < jlen; j++){
24262 var f = fields.items[j];
24263 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24265 values[f.name] = v;
24267 var record = new recordType(values, id);
24269 records[records.length] = record;
24275 totalRecords : totalRecords || records.length
24280 * Ext JS Library 1.1.1
24281 * Copyright(c) 2006-2007, Ext JS, LLC.
24283 * Originally Released Under LGPL - original licence link has changed is not relivant.
24286 * <script type="text/javascript">
24290 * @class Roo.data.ArrayReader
24291 * @extends Roo.data.DataReader
24292 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24293 * Each element of that Array represents a row of data fields. The
24294 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24295 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24299 var RecordDef = Roo.data.Record.create([
24300 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24301 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24303 var myReader = new Roo.data.ArrayReader({
24304 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24308 * This would consume an Array like this:
24310 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24312 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24314 * Create a new JsonReader
24315 * @param {Object} meta Metadata configuration options.
24316 * @param {Object} recordType Either an Array of field definition objects
24317 * as specified to {@link Roo.data.Record#create},
24318 * or an {@link Roo.data.Record} object
24319 * created using {@link Roo.data.Record#create}.
24321 Roo.data.ArrayReader = function(meta, recordType){
24322 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24325 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24327 * Create a data block containing Roo.data.Records from an XML document.
24328 * @param {Object} o An Array of row objects which represents the dataset.
24329 * @return {Object} data A data block which is used by an Roo.data.Store object as
24330 * a cache of Roo.data.Records.
24332 readRecords : function(o){
24333 var sid = this.meta ? this.meta.id : null;
24334 var recordType = this.recordType, fields = recordType.prototype.fields;
24337 for(var i = 0; i < root.length; i++){
24340 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24341 for(var j = 0, jlen = fields.length; j < jlen; j++){
24342 var f = fields.items[j];
24343 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24344 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24346 values[f.name] = v;
24348 var record = new recordType(values, id);
24350 records[records.length] = record;
24354 totalRecords : records.length
24359 * Ext JS Library 1.1.1
24360 * Copyright(c) 2006-2007, Ext JS, LLC.
24362 * Originally Released Under LGPL - original licence link has changed is not relivant.
24365 * <script type="text/javascript">
24370 * @class Roo.data.Tree
24371 * @extends Roo.util.Observable
24372 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24373 * in the tree have most standard DOM functionality.
24375 * @param {Node} root (optional) The root node
24377 Roo.data.Tree = function(root){
24378 this.nodeHash = {};
24380 * The root node for this tree
24385 this.setRootNode(root);
24390 * Fires when a new child node is appended to a node in this tree.
24391 * @param {Tree} tree The owner tree
24392 * @param {Node} parent The parent node
24393 * @param {Node} node The newly appended node
24394 * @param {Number} index The index of the newly appended node
24399 * Fires when a child node is removed from a node in this tree.
24400 * @param {Tree} tree The owner tree
24401 * @param {Node} parent The parent node
24402 * @param {Node} node The child node removed
24407 * Fires when a node is moved to a new location in the tree
24408 * @param {Tree} tree The owner tree
24409 * @param {Node} node The node moved
24410 * @param {Node} oldParent The old parent of this node
24411 * @param {Node} newParent The new parent of this node
24412 * @param {Number} index The index it was moved to
24417 * Fires when a new child node is inserted in a node in this tree.
24418 * @param {Tree} tree The owner tree
24419 * @param {Node} parent The parent node
24420 * @param {Node} node The child node inserted
24421 * @param {Node} refNode The child node the node was inserted before
24425 * @event beforeappend
24426 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24427 * @param {Tree} tree The owner tree
24428 * @param {Node} parent The parent node
24429 * @param {Node} node The child node to be appended
24431 "beforeappend" : true,
24433 * @event beforeremove
24434 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24435 * @param {Tree} tree The owner tree
24436 * @param {Node} parent The parent node
24437 * @param {Node} node The child node to be removed
24439 "beforeremove" : true,
24441 * @event beforemove
24442 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24443 * @param {Tree} tree The owner tree
24444 * @param {Node} node The node being moved
24445 * @param {Node} oldParent The parent of the node
24446 * @param {Node} newParent The new parent the node is moving to
24447 * @param {Number} index The index it is being moved to
24449 "beforemove" : true,
24451 * @event beforeinsert
24452 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24453 * @param {Tree} tree The owner tree
24454 * @param {Node} parent The parent node
24455 * @param {Node} node The child node to be inserted
24456 * @param {Node} refNode The child node the node is being inserted before
24458 "beforeinsert" : true
24461 Roo.data.Tree.superclass.constructor.call(this);
24464 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24465 pathSeparator: "/",
24467 proxyNodeEvent : function(){
24468 return this.fireEvent.apply(this, arguments);
24472 * Returns the root node for this tree.
24475 getRootNode : function(){
24480 * Sets the root node for this tree.
24481 * @param {Node} node
24484 setRootNode : function(node){
24486 node.ownerTree = this;
24487 node.isRoot = true;
24488 this.registerNode(node);
24493 * Gets a node in this tree by its id.
24494 * @param {String} id
24497 getNodeById : function(id){
24498 return this.nodeHash[id];
24501 registerNode : function(node){
24502 this.nodeHash[node.id] = node;
24505 unregisterNode : function(node){
24506 delete this.nodeHash[node.id];
24509 toString : function(){
24510 return "[Tree"+(this.id?" "+this.id:"")+"]";
24515 * @class Roo.data.Node
24516 * @extends Roo.util.Observable
24517 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24518 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24520 * @param {Object} attributes The attributes/config for the node
24522 Roo.data.Node = function(attributes){
24524 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24527 this.attributes = attributes || {};
24528 this.leaf = this.attributes.leaf;
24530 * The node id. @type String
24532 this.id = this.attributes.id;
24534 this.id = Roo.id(null, "ynode-");
24535 this.attributes.id = this.id;
24540 * All child nodes of this node. @type Array
24542 this.childNodes = [];
24543 if(!this.childNodes.indexOf){ // indexOf is a must
24544 this.childNodes.indexOf = function(o){
24545 for(var i = 0, len = this.length; i < len; i++){
24554 * The parent node for this node. @type Node
24556 this.parentNode = null;
24558 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24560 this.firstChild = null;
24562 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24564 this.lastChild = null;
24566 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24568 this.previousSibling = null;
24570 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24572 this.nextSibling = null;
24577 * Fires when a new child node is appended
24578 * @param {Tree} tree The owner tree
24579 * @param {Node} this This node
24580 * @param {Node} node The newly appended node
24581 * @param {Number} index The index of the newly appended node
24586 * Fires when a child node is removed
24587 * @param {Tree} tree The owner tree
24588 * @param {Node} this This node
24589 * @param {Node} node The removed node
24594 * Fires when this node is moved to a new location in the tree
24595 * @param {Tree} tree The owner tree
24596 * @param {Node} this This node
24597 * @param {Node} oldParent The old parent of this node
24598 * @param {Node} newParent The new parent of this node
24599 * @param {Number} index The index it was moved to
24604 * Fires when a new child node is inserted.
24605 * @param {Tree} tree The owner tree
24606 * @param {Node} this This node
24607 * @param {Node} node The child node inserted
24608 * @param {Node} refNode The child node the node was inserted before
24612 * @event beforeappend
24613 * Fires before a new child is appended, return false to cancel the append.
24614 * @param {Tree} tree The owner tree
24615 * @param {Node} this This node
24616 * @param {Node} node The child node to be appended
24618 "beforeappend" : true,
24620 * @event beforeremove
24621 * Fires before a child is removed, return false to cancel the remove.
24622 * @param {Tree} tree The owner tree
24623 * @param {Node} this This node
24624 * @param {Node} node The child node to be removed
24626 "beforeremove" : true,
24628 * @event beforemove
24629 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24630 * @param {Tree} tree The owner tree
24631 * @param {Node} this This node
24632 * @param {Node} oldParent The parent of this node
24633 * @param {Node} newParent The new parent this node is moving to
24634 * @param {Number} index The index it is being moved to
24636 "beforemove" : true,
24638 * @event beforeinsert
24639 * Fires before a new child is inserted, return false to cancel the insert.
24640 * @param {Tree} tree The owner tree
24641 * @param {Node} this This node
24642 * @param {Node} node The child node to be inserted
24643 * @param {Node} refNode The child node the node is being inserted before
24645 "beforeinsert" : true
24647 this.listeners = this.attributes.listeners;
24648 Roo.data.Node.superclass.constructor.call(this);
24651 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24652 fireEvent : function(evtName){
24653 // first do standard event for this node
24654 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24657 // then bubble it up to the tree if the event wasn't cancelled
24658 var ot = this.getOwnerTree();
24660 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24668 * Returns true if this node is a leaf
24669 * @return {Boolean}
24671 isLeaf : function(){
24672 return this.leaf === true;
24676 setFirstChild : function(node){
24677 this.firstChild = node;
24681 setLastChild : function(node){
24682 this.lastChild = node;
24687 * Returns true if this node is the last child of its parent
24688 * @return {Boolean}
24690 isLast : function(){
24691 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24695 * Returns true if this node is the first child of its parent
24696 * @return {Boolean}
24698 isFirst : function(){
24699 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24702 hasChildNodes : function(){
24703 return !this.isLeaf() && this.childNodes.length > 0;
24707 * Insert node(s) as the last child node of this node.
24708 * @param {Node/Array} node The node or Array of nodes to append
24709 * @return {Node} The appended node if single append, or null if an array was passed
24711 appendChild : function(node){
24713 if(node instanceof Array){
24715 }else if(arguments.length > 1){
24718 // if passed an array or multiple args do them one by one
24720 for(var i = 0, len = multi.length; i < len; i++) {
24721 this.appendChild(multi[i]);
24724 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24727 var index = this.childNodes.length;
24728 var oldParent = node.parentNode;
24729 // it's a move, make sure we move it cleanly
24731 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24734 oldParent.removeChild(node);
24736 index = this.childNodes.length;
24738 this.setFirstChild(node);
24740 this.childNodes.push(node);
24741 node.parentNode = this;
24742 var ps = this.childNodes[index-1];
24744 node.previousSibling = ps;
24745 ps.nextSibling = node;
24747 node.previousSibling = null;
24749 node.nextSibling = null;
24750 this.setLastChild(node);
24751 node.setOwnerTree(this.getOwnerTree());
24752 this.fireEvent("append", this.ownerTree, this, node, index);
24754 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24761 * Removes a child node from this node.
24762 * @param {Node} node The node to remove
24763 * @return {Node} The removed node
24765 removeChild : function(node){
24766 var index = this.childNodes.indexOf(node);
24770 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24774 // remove it from childNodes collection
24775 this.childNodes.splice(index, 1);
24778 if(node.previousSibling){
24779 node.previousSibling.nextSibling = node.nextSibling;
24781 if(node.nextSibling){
24782 node.nextSibling.previousSibling = node.previousSibling;
24785 // update child refs
24786 if(this.firstChild == node){
24787 this.setFirstChild(node.nextSibling);
24789 if(this.lastChild == node){
24790 this.setLastChild(node.previousSibling);
24793 node.setOwnerTree(null);
24794 // clear any references from the node
24795 node.parentNode = null;
24796 node.previousSibling = null;
24797 node.nextSibling = null;
24798 this.fireEvent("remove", this.ownerTree, this, node);
24803 * Inserts the first node before the second node in this nodes childNodes collection.
24804 * @param {Node} node The node to insert
24805 * @param {Node} refNode The node to insert before (if null the node is appended)
24806 * @return {Node} The inserted node
24808 insertBefore : function(node, refNode){
24809 if(!refNode){ // like standard Dom, refNode can be null for append
24810 return this.appendChild(node);
24813 if(node == refNode){
24817 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24820 var index = this.childNodes.indexOf(refNode);
24821 var oldParent = node.parentNode;
24822 var refIndex = index;
24824 // when moving internally, indexes will change after remove
24825 if(oldParent == this && this.childNodes.indexOf(node) < index){
24829 // it's a move, make sure we move it cleanly
24831 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24834 oldParent.removeChild(node);
24837 this.setFirstChild(node);
24839 this.childNodes.splice(refIndex, 0, node);
24840 node.parentNode = this;
24841 var ps = this.childNodes[refIndex-1];
24843 node.previousSibling = ps;
24844 ps.nextSibling = node;
24846 node.previousSibling = null;
24848 node.nextSibling = refNode;
24849 refNode.previousSibling = node;
24850 node.setOwnerTree(this.getOwnerTree());
24851 this.fireEvent("insert", this.ownerTree, this, node, refNode);
24853 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
24859 * Returns the child node at the specified index.
24860 * @param {Number} index
24863 item : function(index){
24864 return this.childNodes[index];
24868 * Replaces one child node in this node with another.
24869 * @param {Node} newChild The replacement node
24870 * @param {Node} oldChild The node to replace
24871 * @return {Node} The replaced node
24873 replaceChild : function(newChild, oldChild){
24874 this.insertBefore(newChild, oldChild);
24875 this.removeChild(oldChild);
24880 * Returns the index of a child node
24881 * @param {Node} node
24882 * @return {Number} The index of the node or -1 if it was not found
24884 indexOf : function(child){
24885 return this.childNodes.indexOf(child);
24889 * Returns the tree this node is in.
24892 getOwnerTree : function(){
24893 // if it doesn't have one, look for one
24894 if(!this.ownerTree){
24898 this.ownerTree = p.ownerTree;
24904 return this.ownerTree;
24908 * Returns depth of this node (the root node has a depth of 0)
24911 getDepth : function(){
24914 while(p.parentNode){
24922 setOwnerTree : function(tree){
24923 // if it's move, we need to update everyone
24924 if(tree != this.ownerTree){
24925 if(this.ownerTree){
24926 this.ownerTree.unregisterNode(this);
24928 this.ownerTree = tree;
24929 var cs = this.childNodes;
24930 for(var i = 0, len = cs.length; i < len; i++) {
24931 cs[i].setOwnerTree(tree);
24934 tree.registerNode(this);
24940 * Returns the path for this node. The path can be used to expand or select this node programmatically.
24941 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
24942 * @return {String} The path
24944 getPath : function(attr){
24945 attr = attr || "id";
24946 var p = this.parentNode;
24947 var b = [this.attributes[attr]];
24949 b.unshift(p.attributes[attr]);
24952 var sep = this.getOwnerTree().pathSeparator;
24953 return sep + b.join(sep);
24957 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
24958 * function call will be the scope provided or the current node. The arguments to the function
24959 * will be the args provided or the current node. If the function returns false at any point,
24960 * the bubble is stopped.
24961 * @param {Function} fn The function to call
24962 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24963 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
24965 bubble : function(fn, scope, args){
24968 if(fn.call(scope || p, args || p) === false){
24976 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
24977 * function call will be the scope provided or the current node. The arguments to the function
24978 * will be the args provided or the current node. If the function returns false at any point,
24979 * the cascade is stopped on that branch.
24980 * @param {Function} fn The function to call
24981 * @param {Object} scope (optional) The scope of the function (defaults to current node)
24982 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
24984 cascade : function(fn, scope, args){
24985 if(fn.call(scope || this, args || this) !== false){
24986 var cs = this.childNodes;
24987 for(var i = 0, len = cs.length; i < len; i++) {
24988 cs[i].cascade(fn, scope, args);
24994 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
24995 * function call will be the scope provided or the current node. The arguments to the function
24996 * will be the args provided or the current node. If the function returns false at any point,
24997 * the iteration stops.
24998 * @param {Function} fn The function to call
24999 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25000 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25002 eachChild : function(fn, scope, args){
25003 var cs = this.childNodes;
25004 for(var i = 0, len = cs.length; i < len; i++) {
25005 if(fn.call(scope || this, args || cs[i]) === false){
25012 * Finds the first child that has the attribute with the specified value.
25013 * @param {String} attribute The attribute name
25014 * @param {Mixed} value The value to search for
25015 * @return {Node} The found child or null if none was found
25017 findChild : function(attribute, value){
25018 var cs = this.childNodes;
25019 for(var i = 0, len = cs.length; i < len; i++) {
25020 if(cs[i].attributes[attribute] == value){
25028 * Finds the first child by a custom function. The child matches if the function passed
25030 * @param {Function} fn
25031 * @param {Object} scope (optional)
25032 * @return {Node} The found child or null if none was found
25034 findChildBy : function(fn, scope){
25035 var cs = this.childNodes;
25036 for(var i = 0, len = cs.length; i < len; i++) {
25037 if(fn.call(scope||cs[i], cs[i]) === true){
25045 * Sorts this nodes children using the supplied sort function
25046 * @param {Function} fn
25047 * @param {Object} scope (optional)
25049 sort : function(fn, scope){
25050 var cs = this.childNodes;
25051 var len = cs.length;
25053 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25055 for(var i = 0; i < len; i++){
25057 n.previousSibling = cs[i-1];
25058 n.nextSibling = cs[i+1];
25060 this.setFirstChild(n);
25063 this.setLastChild(n);
25070 * Returns true if this node is an ancestor (at any point) of the passed node.
25071 * @param {Node} node
25072 * @return {Boolean}
25074 contains : function(node){
25075 return node.isAncestor(this);
25079 * Returns true if the passed node is an ancestor (at any point) of this node.
25080 * @param {Node} node
25081 * @return {Boolean}
25083 isAncestor : function(node){
25084 var p = this.parentNode;
25094 toString : function(){
25095 return "[Node"+(this.id?" "+this.id:"")+"]";
25099 * Ext JS Library 1.1.1
25100 * Copyright(c) 2006-2007, Ext JS, LLC.
25102 * Originally Released Under LGPL - original licence link has changed is not relivant.
25105 * <script type="text/javascript">
25110 * @extends Roo.Element
25111 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25112 * automatic maintaining of shadow/shim positions.
25113 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25114 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25115 * you can pass a string with a CSS class name. False turns off the shadow.
25116 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25117 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25118 * @cfg {String} cls CSS class to add to the element
25119 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25120 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25122 * @param {Object} config An object with config options.
25123 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25126 Roo.Layer = function(config, existingEl){
25127 config = config || {};
25128 var dh = Roo.DomHelper;
25129 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25131 this.dom = Roo.getDom(existingEl);
25134 var o = config.dh || {tag: "div", cls: "x-layer"};
25135 this.dom = dh.append(pel, o);
25138 this.addClass(config.cls);
25140 this.constrain = config.constrain !== false;
25141 this.visibilityMode = Roo.Element.VISIBILITY;
25143 this.id = this.dom.id = config.id;
25145 this.id = Roo.id(this.dom);
25147 this.zindex = config.zindex || this.getZIndex();
25148 this.position("absolute", this.zindex);
25150 this.shadowOffset = config.shadowOffset || 4;
25151 this.shadow = new Roo.Shadow({
25152 offset : this.shadowOffset,
25153 mode : config.shadow
25156 this.shadowOffset = 0;
25158 this.useShim = config.shim !== false && Roo.useShims;
25159 this.useDisplay = config.useDisplay;
25163 var supr = Roo.Element.prototype;
25165 // shims are shared among layer to keep from having 100 iframes
25168 Roo.extend(Roo.Layer, Roo.Element, {
25170 getZIndex : function(){
25171 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25174 getShim : function(){
25181 var shim = shims.shift();
25183 shim = this.createShim();
25184 shim.enableDisplayMode('block');
25185 shim.dom.style.display = 'none';
25186 shim.dom.style.visibility = 'visible';
25188 var pn = this.dom.parentNode;
25189 if(shim.dom.parentNode != pn){
25190 pn.insertBefore(shim.dom, this.dom);
25192 shim.setStyle('z-index', this.getZIndex()-2);
25197 hideShim : function(){
25199 this.shim.setDisplayed(false);
25200 shims.push(this.shim);
25205 disableShadow : function(){
25207 this.shadowDisabled = true;
25208 this.shadow.hide();
25209 this.lastShadowOffset = this.shadowOffset;
25210 this.shadowOffset = 0;
25214 enableShadow : function(show){
25216 this.shadowDisabled = false;
25217 this.shadowOffset = this.lastShadowOffset;
25218 delete this.lastShadowOffset;
25226 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25227 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25228 sync : function(doShow){
25229 var sw = this.shadow;
25230 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25231 var sh = this.getShim();
25233 var w = this.getWidth(),
25234 h = this.getHeight();
25236 var l = this.getLeft(true),
25237 t = this.getTop(true);
25239 if(sw && !this.shadowDisabled){
25240 if(doShow && !sw.isVisible()){
25243 sw.realign(l, t, w, h);
25249 // fit the shim behind the shadow, so it is shimmed too
25250 var a = sw.adjusts, s = sh.dom.style;
25251 s.left = (Math.min(l, l+a.l))+"px";
25252 s.top = (Math.min(t, t+a.t))+"px";
25253 s.width = (w+a.w)+"px";
25254 s.height = (h+a.h)+"px";
25261 sh.setLeftTop(l, t);
25268 destroy : function(){
25271 this.shadow.hide();
25273 this.removeAllListeners();
25274 var pn = this.dom.parentNode;
25276 pn.removeChild(this.dom);
25278 Roo.Element.uncache(this.id);
25281 remove : function(){
25286 beginUpdate : function(){
25287 this.updating = true;
25291 endUpdate : function(){
25292 this.updating = false;
25297 hideUnders : function(negOffset){
25299 this.shadow.hide();
25305 constrainXY : function(){
25306 if(this.constrain){
25307 var vw = Roo.lib.Dom.getViewWidth(),
25308 vh = Roo.lib.Dom.getViewHeight();
25309 var s = Roo.get(document).getScroll();
25311 var xy = this.getXY();
25312 var x = xy[0], y = xy[1];
25313 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25314 // only move it if it needs it
25316 // first validate right/bottom
25317 if((x + w) > vw+s.left){
25318 x = vw - w - this.shadowOffset;
25321 if((y + h) > vh+s.top){
25322 y = vh - h - this.shadowOffset;
25325 // then make sure top/left isn't negative
25336 var ay = this.avoidY;
25337 if(y <= ay && (y+h) >= ay){
25343 supr.setXY.call(this, xy);
25349 isVisible : function(){
25350 return this.visible;
25354 showAction : function(){
25355 this.visible = true; // track visibility to prevent getStyle calls
25356 if(this.useDisplay === true){
25357 this.setDisplayed("");
25358 }else if(this.lastXY){
25359 supr.setXY.call(this, this.lastXY);
25360 }else if(this.lastLT){
25361 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25366 hideAction : function(){
25367 this.visible = false;
25368 if(this.useDisplay === true){
25369 this.setDisplayed(false);
25371 this.setLeftTop(-10000,-10000);
25375 // overridden Element method
25376 setVisible : function(v, a, d, c, e){
25381 var cb = function(){
25386 }.createDelegate(this);
25387 supr.setVisible.call(this, true, true, d, cb, e);
25390 this.hideUnders(true);
25399 }.createDelegate(this);
25401 supr.setVisible.call(this, v, a, d, cb, e);
25410 storeXY : function(xy){
25411 delete this.lastLT;
25415 storeLeftTop : function(left, top){
25416 delete this.lastXY;
25417 this.lastLT = [left, top];
25421 beforeFx : function(){
25422 this.beforeAction();
25423 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25427 afterFx : function(){
25428 Roo.Layer.superclass.afterFx.apply(this, arguments);
25429 this.sync(this.isVisible());
25433 beforeAction : function(){
25434 if(!this.updating && this.shadow){
25435 this.shadow.hide();
25439 // overridden Element method
25440 setLeft : function(left){
25441 this.storeLeftTop(left, this.getTop(true));
25442 supr.setLeft.apply(this, arguments);
25446 setTop : function(top){
25447 this.storeLeftTop(this.getLeft(true), top);
25448 supr.setTop.apply(this, arguments);
25452 setLeftTop : function(left, top){
25453 this.storeLeftTop(left, top);
25454 supr.setLeftTop.apply(this, arguments);
25458 setXY : function(xy, a, d, c, e){
25460 this.beforeAction();
25462 var cb = this.createCB(c);
25463 supr.setXY.call(this, xy, a, d, cb, e);
25470 createCB : function(c){
25481 // overridden Element method
25482 setX : function(x, a, d, c, e){
25483 this.setXY([x, this.getY()], a, d, c, e);
25486 // overridden Element method
25487 setY : function(y, a, d, c, e){
25488 this.setXY([this.getX(), y], a, d, c, e);
25491 // overridden Element method
25492 setSize : function(w, h, a, d, c, e){
25493 this.beforeAction();
25494 var cb = this.createCB(c);
25495 supr.setSize.call(this, w, h, a, d, cb, e);
25501 // overridden Element method
25502 setWidth : function(w, a, d, c, e){
25503 this.beforeAction();
25504 var cb = this.createCB(c);
25505 supr.setWidth.call(this, w, a, d, cb, e);
25511 // overridden Element method
25512 setHeight : function(h, a, d, c, e){
25513 this.beforeAction();
25514 var cb = this.createCB(c);
25515 supr.setHeight.call(this, h, a, d, cb, e);
25521 // overridden Element method
25522 setBounds : function(x, y, w, h, a, d, c, e){
25523 this.beforeAction();
25524 var cb = this.createCB(c);
25526 this.storeXY([x, y]);
25527 supr.setXY.call(this, [x, y]);
25528 supr.setSize.call(this, w, h, a, d, cb, e);
25531 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25537 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25538 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25539 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25540 * @param {Number} zindex The new z-index to set
25541 * @return {this} The Layer
25543 setZIndex : function(zindex){
25544 this.zindex = zindex;
25545 this.setStyle("z-index", zindex + 2);
25547 this.shadow.setZIndex(zindex + 1);
25550 this.shim.setStyle("z-index", zindex);
25556 * Ext JS Library 1.1.1
25557 * Copyright(c) 2006-2007, Ext JS, LLC.
25559 * Originally Released Under LGPL - original licence link has changed is not relivant.
25562 * <script type="text/javascript">
25567 * @class Roo.Shadow
25568 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25569 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25570 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25572 * Create a new Shadow
25573 * @param {Object} config The config object
25575 Roo.Shadow = function(config){
25576 Roo.apply(this, config);
25577 if(typeof this.mode != "string"){
25578 this.mode = this.defaultMode;
25580 var o = this.offset, a = {h: 0};
25581 var rad = Math.floor(this.offset/2);
25582 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25588 a.l -= this.offset + rad;
25589 a.t -= this.offset + rad;
25600 a.l -= (this.offset - rad);
25601 a.t -= this.offset + rad;
25603 a.w -= (this.offset - rad)*2;
25614 a.l -= (this.offset - rad);
25615 a.t -= (this.offset - rad);
25617 a.w -= (this.offset + rad + 1);
25618 a.h -= (this.offset + rad);
25627 Roo.Shadow.prototype = {
25629 * @cfg {String} mode
25630 * The shadow display mode. Supports the following options:<br />
25631 * sides: Shadow displays on both sides and bottom only<br />
25632 * frame: Shadow displays equally on all four sides<br />
25633 * drop: Traditional bottom-right drop shadow (default)
25636 * @cfg {String} offset
25637 * The number of pixels to offset the shadow from the element (defaults to 4)
25642 defaultMode: "drop",
25645 * Displays the shadow under the target element
25646 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25648 show : function(target){
25649 target = Roo.get(target);
25651 this.el = Roo.Shadow.Pool.pull();
25652 if(this.el.dom.nextSibling != target.dom){
25653 this.el.insertBefore(target);
25656 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25658 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25661 target.getLeft(true),
25662 target.getTop(true),
25666 this.el.dom.style.display = "block";
25670 * Returns true if the shadow is visible, else false
25672 isVisible : function(){
25673 return this.el ? true : false;
25677 * Direct alignment when values are already available. Show must be called at least once before
25678 * calling this method to ensure it is initialized.
25679 * @param {Number} left The target element left position
25680 * @param {Number} top The target element top position
25681 * @param {Number} width The target element width
25682 * @param {Number} height The target element height
25684 realign : function(l, t, w, h){
25688 var a = this.adjusts, d = this.el.dom, s = d.style;
25690 s.left = (l+a.l)+"px";
25691 s.top = (t+a.t)+"px";
25692 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25694 if(s.width != sws || s.height != shs){
25698 var cn = d.childNodes;
25699 var sww = Math.max(0, (sw-12))+"px";
25700 cn[0].childNodes[1].style.width = sww;
25701 cn[1].childNodes[1].style.width = sww;
25702 cn[2].childNodes[1].style.width = sww;
25703 cn[1].style.height = Math.max(0, (sh-12))+"px";
25709 * Hides this shadow
25713 this.el.dom.style.display = "none";
25714 Roo.Shadow.Pool.push(this.el);
25720 * Adjust the z-index of this shadow
25721 * @param {Number} zindex The new z-index
25723 setZIndex : function(z){
25726 this.el.setStyle("z-index", z);
25731 // Private utility class that manages the internal Shadow cache
25732 Roo.Shadow.Pool = function(){
25734 var markup = Roo.isIE ?
25735 '<div class="x-ie-shadow"></div>' :
25736 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
25739 var sh = p.shift();
25741 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25742 sh.autoBoxAdjust = false;
25747 push : function(sh){
25753 * Ext JS Library 1.1.1
25754 * Copyright(c) 2006-2007, Ext JS, LLC.
25756 * Originally Released Under LGPL - original licence link has changed is not relivant.
25759 * <script type="text/javascript">
25764 * @class Roo.SplitBar
25765 * @extends Roo.util.Observable
25766 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25770 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25771 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25772 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25773 split.minSize = 100;
25774 split.maxSize = 600;
25775 split.animate = true;
25776 split.on('moved', splitterMoved);
25779 * Create a new SplitBar
25780 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25781 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25782 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25783 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25784 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25785 position of the SplitBar).
25787 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25790 this.el = Roo.get(dragElement, true);
25791 this.el.dom.unselectable = "on";
25793 this.resizingEl = Roo.get(resizingElement, true);
25797 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25798 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25801 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25804 * The minimum size of the resizing element. (Defaults to 0)
25810 * The maximum size of the resizing element. (Defaults to 2000)
25813 this.maxSize = 2000;
25816 * Whether to animate the transition to the new size
25819 this.animate = false;
25822 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25825 this.useShim = false;
25830 if(!existingProxy){
25832 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25834 this.proxy = Roo.get(existingProxy).dom;
25837 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25840 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25843 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25846 this.dragSpecs = {};
25849 * @private The adapter to use to positon and resize elements
25851 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
25852 this.adapter.init(this);
25854 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25856 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
25857 this.el.addClass("x-splitbar-h");
25860 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
25861 this.el.addClass("x-splitbar-v");
25867 * Fires when the splitter is moved (alias for {@link #event-moved})
25868 * @param {Roo.SplitBar} this
25869 * @param {Number} newSize the new width or height
25874 * Fires when the splitter is moved
25875 * @param {Roo.SplitBar} this
25876 * @param {Number} newSize the new width or height
25880 * @event beforeresize
25881 * Fires before the splitter is dragged
25882 * @param {Roo.SplitBar} this
25884 "beforeresize" : true,
25886 "beforeapply" : true
25889 Roo.util.Observable.call(this);
25892 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
25893 onStartProxyDrag : function(x, y){
25894 this.fireEvent("beforeresize", this);
25896 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
25898 o.enableDisplayMode("block");
25899 // all splitbars share the same overlay
25900 Roo.SplitBar.prototype.overlay = o;
25902 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
25903 this.overlay.show();
25904 Roo.get(this.proxy).setDisplayed("block");
25905 var size = this.adapter.getElementSize(this);
25906 this.activeMinSize = this.getMinimumSize();;
25907 this.activeMaxSize = this.getMaximumSize();;
25908 var c1 = size - this.activeMinSize;
25909 var c2 = Math.max(this.activeMaxSize - size, 0);
25910 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25911 this.dd.resetConstraints();
25912 this.dd.setXConstraint(
25913 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
25914 this.placement == Roo.SplitBar.LEFT ? c2 : c1
25916 this.dd.setYConstraint(0, 0);
25918 this.dd.resetConstraints();
25919 this.dd.setXConstraint(0, 0);
25920 this.dd.setYConstraint(
25921 this.placement == Roo.SplitBar.TOP ? c1 : c2,
25922 this.placement == Roo.SplitBar.TOP ? c2 : c1
25925 this.dragSpecs.startSize = size;
25926 this.dragSpecs.startPoint = [x, y];
25927 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
25931 * @private Called after the drag operation by the DDProxy
25933 onEndProxyDrag : function(e){
25934 Roo.get(this.proxy).setDisplayed(false);
25935 var endPoint = Roo.lib.Event.getXY(e);
25937 this.overlay.hide();
25940 if(this.orientation == Roo.SplitBar.HORIZONTAL){
25941 newSize = this.dragSpecs.startSize +
25942 (this.placement == Roo.SplitBar.LEFT ?
25943 endPoint[0] - this.dragSpecs.startPoint[0] :
25944 this.dragSpecs.startPoint[0] - endPoint[0]
25947 newSize = this.dragSpecs.startSize +
25948 (this.placement == Roo.SplitBar.TOP ?
25949 endPoint[1] - this.dragSpecs.startPoint[1] :
25950 this.dragSpecs.startPoint[1] - endPoint[1]
25953 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
25954 if(newSize != this.dragSpecs.startSize){
25955 if(this.fireEvent('beforeapply', this, newSize) !== false){
25956 this.adapter.setElementSize(this, newSize);
25957 this.fireEvent("moved", this, newSize);
25958 this.fireEvent("resize", this, newSize);
25964 * Get the adapter this SplitBar uses
25965 * @return The adapter object
25967 getAdapter : function(){
25968 return this.adapter;
25972 * Set the adapter this SplitBar uses
25973 * @param {Object} adapter A SplitBar adapter object
25975 setAdapter : function(adapter){
25976 this.adapter = adapter;
25977 this.adapter.init(this);
25981 * Gets the minimum size for the resizing element
25982 * @return {Number} The minimum size
25984 getMinimumSize : function(){
25985 return this.minSize;
25989 * Sets the minimum size for the resizing element
25990 * @param {Number} minSize The minimum size
25992 setMinimumSize : function(minSize){
25993 this.minSize = minSize;
25997 * Gets the maximum size for the resizing element
25998 * @return {Number} The maximum size
26000 getMaximumSize : function(){
26001 return this.maxSize;
26005 * Sets the maximum size for the resizing element
26006 * @param {Number} maxSize The maximum size
26008 setMaximumSize : function(maxSize){
26009 this.maxSize = maxSize;
26013 * Sets the initialize size for the resizing element
26014 * @param {Number} size The initial size
26016 setCurrentSize : function(size){
26017 var oldAnimate = this.animate;
26018 this.animate = false;
26019 this.adapter.setElementSize(this, size);
26020 this.animate = oldAnimate;
26024 * Destroy this splitbar.
26025 * @param {Boolean} removeEl True to remove the element
26027 destroy : function(removeEl){
26029 this.shim.remove();
26032 this.proxy.parentNode.removeChild(this.proxy);
26040 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
26042 Roo.SplitBar.createProxy = function(dir){
26043 var proxy = new Roo.Element(document.createElement("div"));
26044 proxy.unselectable();
26045 var cls = 'x-splitbar-proxy';
26046 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26047 document.body.appendChild(proxy.dom);
26052 * @class Roo.SplitBar.BasicLayoutAdapter
26053 * Default Adapter. It assumes the splitter and resizing element are not positioned
26054 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26056 Roo.SplitBar.BasicLayoutAdapter = function(){
26059 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26060 // do nothing for now
26061 init : function(s){
26065 * Called before drag operations to get the current size of the resizing element.
26066 * @param {Roo.SplitBar} s The SplitBar using this adapter
26068 getElementSize : function(s){
26069 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26070 return s.resizingEl.getWidth();
26072 return s.resizingEl.getHeight();
26077 * Called after drag operations to set the size of the resizing element.
26078 * @param {Roo.SplitBar} s The SplitBar using this adapter
26079 * @param {Number} newSize The new size to set
26080 * @param {Function} onComplete A function to be invoked when resizing is complete
26082 setElementSize : function(s, newSize, onComplete){
26083 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26085 s.resizingEl.setWidth(newSize);
26087 onComplete(s, newSize);
26090 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26095 s.resizingEl.setHeight(newSize);
26097 onComplete(s, newSize);
26100 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26107 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26108 * @extends Roo.SplitBar.BasicLayoutAdapter
26109 * Adapter that moves the splitter element to align with the resized sizing element.
26110 * Used with an absolute positioned SplitBar.
26111 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26112 * document.body, make sure you assign an id to the body element.
26114 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26115 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26116 this.container = Roo.get(container);
26119 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26120 init : function(s){
26121 this.basic.init(s);
26124 getElementSize : function(s){
26125 return this.basic.getElementSize(s);
26128 setElementSize : function(s, newSize, onComplete){
26129 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26132 moveSplitter : function(s){
26133 var yes = Roo.SplitBar;
26134 switch(s.placement){
26136 s.el.setX(s.resizingEl.getRight());
26139 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26142 s.el.setY(s.resizingEl.getBottom());
26145 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26152 * Orientation constant - Create a vertical SplitBar
26156 Roo.SplitBar.VERTICAL = 1;
26159 * Orientation constant - Create a horizontal SplitBar
26163 Roo.SplitBar.HORIZONTAL = 2;
26166 * Placement constant - The resizing element is to the left of the splitter element
26170 Roo.SplitBar.LEFT = 1;
26173 * Placement constant - The resizing element is to the right of the splitter element
26177 Roo.SplitBar.RIGHT = 2;
26180 * Placement constant - The resizing element is positioned above the splitter element
26184 Roo.SplitBar.TOP = 3;
26187 * Placement constant - The resizing element is positioned under splitter element
26191 Roo.SplitBar.BOTTOM = 4;
26194 * Ext JS Library 1.1.1
26195 * Copyright(c) 2006-2007, Ext JS, LLC.
26197 * Originally Released Under LGPL - original licence link has changed is not relivant.
26200 * <script type="text/javascript">
26205 * @extends Roo.util.Observable
26206 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26207 * This class also supports single and multi selection modes. <br>
26208 * Create a data model bound view:
26210 var store = new Roo.data.Store(...);
26212 var view = new Roo.View({
26214 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26216 singleSelect: true,
26217 selectedClass: "ydataview-selected",
26221 // listen for node click?
26222 view.on("click", function(vw, index, node, e){
26223 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26227 dataModel.load("foobar.xml");
26229 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26231 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26232 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26234 * Note: old style constructor is still suported (container, template, config)
26237 * Create a new View
26238 * @param {Object} config The config object
26241 Roo.View = function(config, depreciated_tpl, depreciated_config){
26243 this.parent = false;
26245 if (typeof(depreciated_tpl) == 'undefined') {
26246 // new way.. - universal constructor.
26247 Roo.apply(this, config);
26248 this.el = Roo.get(this.el);
26251 this.el = Roo.get(config);
26252 this.tpl = depreciated_tpl;
26253 Roo.apply(this, depreciated_config);
26255 this.wrapEl = this.el.wrap().wrap();
26256 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26259 if(typeof(this.tpl) == "string"){
26260 this.tpl = new Roo.Template(this.tpl);
26262 // support xtype ctors..
26263 this.tpl = new Roo.factory(this.tpl, Roo);
26267 this.tpl.compile();
26272 * @event beforeclick
26273 * Fires before a click is processed. Returns false to cancel the default action.
26274 * @param {Roo.View} this
26275 * @param {Number} index The index of the target node
26276 * @param {HTMLElement} node The target node
26277 * @param {Roo.EventObject} e The raw event object
26279 "beforeclick" : true,
26282 * Fires when a template node is clicked.
26283 * @param {Roo.View} this
26284 * @param {Number} index The index of the target node
26285 * @param {HTMLElement} node The target node
26286 * @param {Roo.EventObject} e The raw event object
26291 * Fires when a template node is double clicked.
26292 * @param {Roo.View} this
26293 * @param {Number} index The index of the target node
26294 * @param {HTMLElement} node The target node
26295 * @param {Roo.EventObject} e The raw event object
26299 * @event contextmenu
26300 * Fires when a template node is right clicked.
26301 * @param {Roo.View} this
26302 * @param {Number} index The index of the target node
26303 * @param {HTMLElement} node The target node
26304 * @param {Roo.EventObject} e The raw event object
26306 "contextmenu" : true,
26308 * @event selectionchange
26309 * Fires when the selected nodes change.
26310 * @param {Roo.View} this
26311 * @param {Array} selections Array of the selected nodes
26313 "selectionchange" : true,
26316 * @event beforeselect
26317 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26318 * @param {Roo.View} this
26319 * @param {HTMLElement} node The node to be selected
26320 * @param {Array} selections Array of currently selected nodes
26322 "beforeselect" : true,
26324 * @event preparedata
26325 * Fires on every row to render, to allow you to change the data.
26326 * @param {Roo.View} this
26327 * @param {Object} data to be rendered (change this)
26329 "preparedata" : true
26337 "click": this.onClick,
26338 "dblclick": this.onDblClick,
26339 "contextmenu": this.onContextMenu,
26343 this.selections = [];
26345 this.cmp = new Roo.CompositeElementLite([]);
26347 this.store = Roo.factory(this.store, Roo.data);
26348 this.setStore(this.store, true);
26351 if ( this.footer && this.footer.xtype) {
26353 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26355 this.footer.dataSource = this.store;
26356 this.footer.container = fctr;
26357 this.footer = Roo.factory(this.footer, Roo);
26358 fctr.insertFirst(this.el);
26360 // this is a bit insane - as the paging toolbar seems to detach the el..
26361 // dom.parentNode.parentNode.parentNode
26362 // they get detached?
26366 Roo.View.superclass.constructor.call(this);
26371 Roo.extend(Roo.View, Roo.util.Observable, {
26374 * @cfg {Roo.data.Store} store Data store to load data from.
26379 * @cfg {String|Roo.Element} el The container element.
26384 * @cfg {String|Roo.Template} tpl The template used by this View
26388 * @cfg {String} dataName the named area of the template to use as the data area
26389 * Works with domtemplates roo-name="name"
26393 * @cfg {String} selectedClass The css class to add to selected nodes
26395 selectedClass : "x-view-selected",
26397 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26402 * @cfg {String} text to display on mask (default Loading)
26406 * @cfg {Boolean} multiSelect Allow multiple selection
26408 multiSelect : false,
26410 * @cfg {Boolean} singleSelect Allow single selection
26412 singleSelect: false,
26415 * @cfg {Boolean} toggleSelect - selecting
26417 toggleSelect : false,
26420 * @cfg {Boolean} tickable - selecting
26425 * Returns the element this view is bound to.
26426 * @return {Roo.Element}
26428 getEl : function(){
26429 return this.wrapEl;
26435 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26437 refresh : function(){
26438 //Roo.log('refresh');
26441 // if we are using something like 'domtemplate', then
26442 // the what gets used is:
26443 // t.applySubtemplate(NAME, data, wrapping data..)
26444 // the outer template then get' applied with
26445 // the store 'extra data'
26446 // and the body get's added to the
26447 // roo-name="data" node?
26448 // <span class='roo-tpl-{name}'></span> ?????
26452 this.clearSelections();
26453 this.el.update("");
26455 var records = this.store.getRange();
26456 if(records.length < 1) {
26458 // is this valid?? = should it render a template??
26460 this.el.update(this.emptyText);
26464 if (this.dataName) {
26465 this.el.update(t.apply(this.store.meta)); //????
26466 el = this.el.child('.roo-tpl-' + this.dataName);
26469 for(var i = 0, len = records.length; i < len; i++){
26470 var data = this.prepareData(records[i].data, i, records[i]);
26471 this.fireEvent("preparedata", this, data, i, records[i]);
26473 var d = Roo.apply({}, data);
26476 Roo.apply(d, {'roo-id' : Roo.id()});
26480 Roo.each(this.parent.item, function(item){
26481 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26484 Roo.apply(d, {'roo-data-checked' : 'checked'});
26488 html[html.length] = Roo.util.Format.trim(
26490 t.applySubtemplate(this.dataName, d, this.store.meta) :
26497 el.update(html.join(""));
26498 this.nodes = el.dom.childNodes;
26499 this.updateIndexes(0);
26504 * Function to override to reformat the data that is sent to
26505 * the template for each node.
26506 * DEPRICATED - use the preparedata event handler.
26507 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26508 * a JSON object for an UpdateManager bound view).
26510 prepareData : function(data, index, record)
26512 this.fireEvent("preparedata", this, data, index, record);
26516 onUpdate : function(ds, record){
26517 // Roo.log('on update');
26518 this.clearSelections();
26519 var index = this.store.indexOf(record);
26520 var n = this.nodes[index];
26521 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26522 n.parentNode.removeChild(n);
26523 this.updateIndexes(index, index);
26529 onAdd : function(ds, records, index)
26531 //Roo.log(['on Add', ds, records, index] );
26532 this.clearSelections();
26533 if(this.nodes.length == 0){
26537 var n = this.nodes[index];
26538 for(var i = 0, len = records.length; i < len; i++){
26539 var d = this.prepareData(records[i].data, i, records[i]);
26541 this.tpl.insertBefore(n, d);
26544 this.tpl.append(this.el, d);
26547 this.updateIndexes(index);
26550 onRemove : function(ds, record, index){
26551 // Roo.log('onRemove');
26552 this.clearSelections();
26553 var el = this.dataName ?
26554 this.el.child('.roo-tpl-' + this.dataName) :
26557 el.dom.removeChild(this.nodes[index]);
26558 this.updateIndexes(index);
26562 * Refresh an individual node.
26563 * @param {Number} index
26565 refreshNode : function(index){
26566 this.onUpdate(this.store, this.store.getAt(index));
26569 updateIndexes : function(startIndex, endIndex){
26570 var ns = this.nodes;
26571 startIndex = startIndex || 0;
26572 endIndex = endIndex || ns.length - 1;
26573 for(var i = startIndex; i <= endIndex; i++){
26574 ns[i].nodeIndex = i;
26579 * Changes the data store this view uses and refresh the view.
26580 * @param {Store} store
26582 setStore : function(store, initial){
26583 if(!initial && this.store){
26584 this.store.un("datachanged", this.refresh);
26585 this.store.un("add", this.onAdd);
26586 this.store.un("remove", this.onRemove);
26587 this.store.un("update", this.onUpdate);
26588 this.store.un("clear", this.refresh);
26589 this.store.un("beforeload", this.onBeforeLoad);
26590 this.store.un("load", this.onLoad);
26591 this.store.un("loadexception", this.onLoad);
26595 store.on("datachanged", this.refresh, this);
26596 store.on("add", this.onAdd, this);
26597 store.on("remove", this.onRemove, this);
26598 store.on("update", this.onUpdate, this);
26599 store.on("clear", this.refresh, this);
26600 store.on("beforeload", this.onBeforeLoad, this);
26601 store.on("load", this.onLoad, this);
26602 store.on("loadexception", this.onLoad, this);
26610 * onbeforeLoad - masks the loading area.
26613 onBeforeLoad : function(store,opts)
26615 //Roo.log('onBeforeLoad');
26617 this.el.update("");
26619 this.el.mask(this.mask ? this.mask : "Loading" );
26621 onLoad : function ()
26628 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26629 * @param {HTMLElement} node
26630 * @return {HTMLElement} The template node
26632 findItemFromChild : function(node){
26633 var el = this.dataName ?
26634 this.el.child('.roo-tpl-' + this.dataName,true) :
26637 if(!node || node.parentNode == el){
26640 var p = node.parentNode;
26641 while(p && p != el){
26642 if(p.parentNode == el){
26651 onClick : function(e){
26652 var item = this.findItemFromChild(e.getTarget());
26654 var index = this.indexOf(item);
26655 if(this.onItemClick(item, index, e) !== false){
26656 this.fireEvent("click", this, index, item, e);
26659 this.clearSelections();
26664 onContextMenu : function(e){
26665 var item = this.findItemFromChild(e.getTarget());
26667 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26672 onDblClick : function(e){
26673 var item = this.findItemFromChild(e.getTarget());
26675 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26679 onItemClick : function(item, index, e)
26681 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26684 if (this.toggleSelect) {
26685 var m = this.isSelected(item) ? 'unselect' : 'select';
26688 _t[m](item, true, false);
26691 if(this.multiSelect || this.singleSelect){
26692 if(this.multiSelect && e.shiftKey && this.lastSelection){
26693 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26695 this.select(item, this.multiSelect && e.ctrlKey);
26696 this.lastSelection = item;
26699 if(!this.tickable){
26700 e.preventDefault();
26708 * Get the number of selected nodes.
26711 getSelectionCount : function(){
26712 return this.selections.length;
26716 * Get the currently selected nodes.
26717 * @return {Array} An array of HTMLElements
26719 getSelectedNodes : function(){
26720 return this.selections;
26724 * Get the indexes of the selected nodes.
26727 getSelectedIndexes : function(){
26728 var indexes = [], s = this.selections;
26729 for(var i = 0, len = s.length; i < len; i++){
26730 indexes.push(s[i].nodeIndex);
26736 * Clear all selections
26737 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26739 clearSelections : function(suppressEvent){
26740 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26741 this.cmp.elements = this.selections;
26742 this.cmp.removeClass(this.selectedClass);
26743 this.selections = [];
26744 if(!suppressEvent){
26745 this.fireEvent("selectionchange", this, this.selections);
26751 * Returns true if the passed node is selected
26752 * @param {HTMLElement/Number} node The node or node index
26753 * @return {Boolean}
26755 isSelected : function(node){
26756 var s = this.selections;
26760 node = this.getNode(node);
26761 return s.indexOf(node) !== -1;
26766 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
26767 * @param {Boolean} keepExisting (optional) true to keep existing selections
26768 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26770 select : function(nodeInfo, keepExisting, suppressEvent){
26771 if(nodeInfo instanceof Array){
26773 this.clearSelections(true);
26775 for(var i = 0, len = nodeInfo.length; i < len; i++){
26776 this.select(nodeInfo[i], true, true);
26780 var node = this.getNode(nodeInfo);
26781 if(!node || this.isSelected(node)){
26782 return; // already selected.
26785 this.clearSelections(true);
26788 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26789 Roo.fly(node).addClass(this.selectedClass);
26790 this.selections.push(node);
26791 if(!suppressEvent){
26792 this.fireEvent("selectionchange", this, this.selections);
26800 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
26801 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26802 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26804 unselect : function(nodeInfo, keepExisting, suppressEvent)
26806 if(nodeInfo instanceof Array){
26807 Roo.each(this.selections, function(s) {
26808 this.unselect(s, nodeInfo);
26812 var node = this.getNode(nodeInfo);
26813 if(!node || !this.isSelected(node)){
26814 //Roo.log("not selected");
26815 return; // not selected.
26819 Roo.each(this.selections, function(s) {
26821 Roo.fly(node).removeClass(this.selectedClass);
26828 this.selections= ns;
26829 this.fireEvent("selectionchange", this, this.selections);
26833 * Gets a template node.
26834 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26835 * @return {HTMLElement} The node or null if it wasn't found
26837 getNode : function(nodeInfo){
26838 if(typeof nodeInfo == "string"){
26839 return document.getElementById(nodeInfo);
26840 }else if(typeof nodeInfo == "number"){
26841 return this.nodes[nodeInfo];
26847 * Gets a range template nodes.
26848 * @param {Number} startIndex
26849 * @param {Number} endIndex
26850 * @return {Array} An array of nodes
26852 getNodes : function(start, end){
26853 var ns = this.nodes;
26854 start = start || 0;
26855 end = typeof end == "undefined" ? ns.length - 1 : end;
26858 for(var i = start; i <= end; i++){
26862 for(var i = start; i >= end; i--){
26870 * Finds the index of the passed node
26871 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26872 * @return {Number} The index of the node or -1
26874 indexOf : function(node){
26875 node = this.getNode(node);
26876 if(typeof node.nodeIndex == "number"){
26877 return node.nodeIndex;
26879 var ns = this.nodes;
26880 for(var i = 0, len = ns.length; i < len; i++){
26890 * Ext JS Library 1.1.1
26891 * Copyright(c) 2006-2007, Ext JS, LLC.
26893 * Originally Released Under LGPL - original licence link has changed is not relivant.
26896 * <script type="text/javascript">
26900 * @class Roo.JsonView
26901 * @extends Roo.View
26902 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
26904 var view = new Roo.JsonView({
26905 container: "my-element",
26906 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
26911 // listen for node click?
26912 view.on("click", function(vw, index, node, e){
26913 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26916 // direct load of JSON data
26917 view.load("foobar.php");
26919 // Example from my blog list
26920 var tpl = new Roo.Template(
26921 '<div class="entry">' +
26922 '<a class="entry-title" href="{link}">{title}</a>' +
26923 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
26924 "</div><hr />"
26927 var moreView = new Roo.JsonView({
26928 container : "entry-list",
26932 moreView.on("beforerender", this.sortEntries, this);
26934 url: "/blog/get-posts.php",
26935 params: "allposts=true",
26936 text: "Loading Blog Entries..."
26940 * Note: old code is supported with arguments : (container, template, config)
26944 * Create a new JsonView
26946 * @param {Object} config The config object
26949 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
26952 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
26954 var um = this.el.getUpdateManager();
26955 um.setRenderer(this);
26956 um.on("update", this.onLoad, this);
26957 um.on("failure", this.onLoadException, this);
26960 * @event beforerender
26961 * Fires before rendering of the downloaded JSON data.
26962 * @param {Roo.JsonView} this
26963 * @param {Object} data The JSON data loaded
26967 * Fires when data is loaded.
26968 * @param {Roo.JsonView} this
26969 * @param {Object} data The JSON data loaded
26970 * @param {Object} response The raw Connect response object
26973 * @event loadexception
26974 * Fires when loading fails.
26975 * @param {Roo.JsonView} this
26976 * @param {Object} response The raw Connect response object
26979 'beforerender' : true,
26981 'loadexception' : true
26984 Roo.extend(Roo.JsonView, Roo.View, {
26986 * @type {String} The root property in the loaded JSON object that contains the data
26991 * Refreshes the view.
26993 refresh : function(){
26994 this.clearSelections();
26995 this.el.update("");
26997 var o = this.jsonData;
26998 if(o && o.length > 0){
26999 for(var i = 0, len = o.length; i < len; i++){
27000 var data = this.prepareData(o[i], i, o);
27001 html[html.length] = this.tpl.apply(data);
27004 html.push(this.emptyText);
27006 this.el.update(html.join(""));
27007 this.nodes = this.el.dom.childNodes;
27008 this.updateIndexes(0);
27012 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
27013 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
27016 url: "your-url.php",
27017 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27018 callback: yourFunction,
27019 scope: yourObject, //(optional scope)
27022 text: "Loading...",
27027 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27028 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
27029 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
27030 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27031 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
27034 var um = this.el.getUpdateManager();
27035 um.update.apply(um, arguments);
27038 // note - render is a standard framework call...
27039 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27040 render : function(el, response){
27042 this.clearSelections();
27043 this.el.update("");
27046 if (response != '') {
27047 o = Roo.util.JSON.decode(response.responseText);
27050 o = o[this.jsonRoot];
27056 * The current JSON data or null
27059 this.beforeRender();
27064 * Get the number of records in the current JSON dataset
27067 getCount : function(){
27068 return this.jsonData ? this.jsonData.length : 0;
27072 * Returns the JSON object for the specified node(s)
27073 * @param {HTMLElement/Array} node The node or an array of nodes
27074 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27075 * you get the JSON object for the node
27077 getNodeData : function(node){
27078 if(node instanceof Array){
27080 for(var i = 0, len = node.length; i < len; i++){
27081 data.push(this.getNodeData(node[i]));
27085 return this.jsonData[this.indexOf(node)] || null;
27088 beforeRender : function(){
27089 this.snapshot = this.jsonData;
27091 this.sort.apply(this, this.sortInfo);
27093 this.fireEvent("beforerender", this, this.jsonData);
27096 onLoad : function(el, o){
27097 this.fireEvent("load", this, this.jsonData, o);
27100 onLoadException : function(el, o){
27101 this.fireEvent("loadexception", this, o);
27105 * Filter the data by a specific property.
27106 * @param {String} property A property on your JSON objects
27107 * @param {String/RegExp} value Either string that the property values
27108 * should start with, or a RegExp to test against the property
27110 filter : function(property, value){
27113 var ss = this.snapshot;
27114 if(typeof value == "string"){
27115 var vlen = value.length;
27117 this.clearFilter();
27120 value = value.toLowerCase();
27121 for(var i = 0, len = ss.length; i < len; i++){
27123 if(o[property].substr(0, vlen).toLowerCase() == value){
27127 } else if(value.exec){ // regex?
27128 for(var i = 0, len = ss.length; i < len; i++){
27130 if(value.test(o[property])){
27137 this.jsonData = data;
27143 * Filter by a function. The passed function will be called with each
27144 * object in the current dataset. If the function returns true the value is kept,
27145 * otherwise it is filtered.
27146 * @param {Function} fn
27147 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27149 filterBy : function(fn, scope){
27152 var ss = this.snapshot;
27153 for(var i = 0, len = ss.length; i < len; i++){
27155 if(fn.call(scope || this, o)){
27159 this.jsonData = data;
27165 * Clears the current filter.
27167 clearFilter : function(){
27168 if(this.snapshot && this.jsonData != this.snapshot){
27169 this.jsonData = this.snapshot;
27176 * Sorts the data for this view and refreshes it.
27177 * @param {String} property A property on your JSON objects to sort on
27178 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27179 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27181 sort : function(property, dir, sortType){
27182 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27185 var dsc = dir && dir.toLowerCase() == "desc";
27186 var f = function(o1, o2){
27187 var v1 = sortType ? sortType(o1[p]) : o1[p];
27188 var v2 = sortType ? sortType(o2[p]) : o2[p];
27191 return dsc ? +1 : -1;
27192 } else if(v1 > v2){
27193 return dsc ? -1 : +1;
27198 this.jsonData.sort(f);
27200 if(this.jsonData != this.snapshot){
27201 this.snapshot.sort(f);
27207 * Ext JS Library 1.1.1
27208 * Copyright(c) 2006-2007, Ext JS, LLC.
27210 * Originally Released Under LGPL - original licence link has changed is not relivant.
27213 * <script type="text/javascript">
27218 * @class Roo.ColorPalette
27219 * @extends Roo.Component
27220 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27221 * Here's an example of typical usage:
27223 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27224 cp.render('my-div');
27226 cp.on('select', function(palette, selColor){
27227 // do something with selColor
27231 * Create a new ColorPalette
27232 * @param {Object} config The config object
27234 Roo.ColorPalette = function(config){
27235 Roo.ColorPalette.superclass.constructor.call(this, config);
27239 * Fires when a color is selected
27240 * @param {ColorPalette} this
27241 * @param {String} color The 6-digit color hex code (without the # symbol)
27247 this.on("select", this.handler, this.scope, true);
27250 Roo.extend(Roo.ColorPalette, Roo.Component, {
27252 * @cfg {String} itemCls
27253 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27255 itemCls : "x-color-palette",
27257 * @cfg {String} value
27258 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27259 * the hex codes are case-sensitive.
27262 clickEvent:'click',
27264 ctype: "Roo.ColorPalette",
27267 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27269 allowReselect : false,
27272 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27273 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27274 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27275 * of colors with the width setting until the box is symmetrical.</p>
27276 * <p>You can override individual colors if needed:</p>
27278 var cp = new Roo.ColorPalette();
27279 cp.colors[0] = "FF0000"; // change the first box to red
27282 Or you can provide a custom array of your own for complete control:
27284 var cp = new Roo.ColorPalette();
27285 cp.colors = ["000000", "993300", "333300"];
27290 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27291 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27292 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27293 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27294 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27298 onRender : function(container, position){
27299 var t = new Roo.MasterTemplate(
27300 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27302 var c = this.colors;
27303 for(var i = 0, len = c.length; i < len; i++){
27306 var el = document.createElement("div");
27307 el.className = this.itemCls;
27309 container.dom.insertBefore(el, position);
27310 this.el = Roo.get(el);
27311 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27312 if(this.clickEvent != 'click'){
27313 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27318 afterRender : function(){
27319 Roo.ColorPalette.superclass.afterRender.call(this);
27321 var s = this.value;
27328 handleClick : function(e, t){
27329 e.preventDefault();
27330 if(!this.disabled){
27331 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27332 this.select(c.toUpperCase());
27337 * Selects the specified color in the palette (fires the select event)
27338 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27340 select : function(color){
27341 color = color.replace("#", "");
27342 if(color != this.value || this.allowReselect){
27345 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27347 el.child("a.color-"+color).addClass("x-color-palette-sel");
27348 this.value = color;
27349 this.fireEvent("select", this, color);
27354 * Ext JS Library 1.1.1
27355 * Copyright(c) 2006-2007, Ext JS, LLC.
27357 * Originally Released Under LGPL - original licence link has changed is not relivant.
27360 * <script type="text/javascript">
27364 * @class Roo.DatePicker
27365 * @extends Roo.Component
27366 * Simple date picker class.
27368 * Create a new DatePicker
27369 * @param {Object} config The config object
27371 Roo.DatePicker = function(config){
27372 Roo.DatePicker.superclass.constructor.call(this, config);
27374 this.value = config && config.value ?
27375 config.value.clearTime() : new Date().clearTime();
27380 * Fires when a date is selected
27381 * @param {DatePicker} this
27382 * @param {Date} date The selected date
27386 * @event monthchange
27387 * Fires when the displayed month changes
27388 * @param {DatePicker} this
27389 * @param {Date} date The selected month
27391 'monthchange': true
27395 this.on("select", this.handler, this.scope || this);
27397 // build the disabledDatesRE
27398 if(!this.disabledDatesRE && this.disabledDates){
27399 var dd = this.disabledDates;
27401 for(var i = 0; i < dd.length; i++){
27403 if(i != dd.length-1) {
27407 this.disabledDatesRE = new RegExp(re + ")");
27411 Roo.extend(Roo.DatePicker, Roo.Component, {
27413 * @cfg {String} todayText
27414 * The text to display on the button that selects the current date (defaults to "Today")
27416 todayText : "Today",
27418 * @cfg {String} okText
27419 * The text to display on the ok button
27421 okText : " OK ", //   to give the user extra clicking room
27423 * @cfg {String} cancelText
27424 * The text to display on the cancel button
27426 cancelText : "Cancel",
27428 * @cfg {String} todayTip
27429 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27431 todayTip : "{0} (Spacebar)",
27433 * @cfg {Date} minDate
27434 * Minimum allowable date (JavaScript date object, defaults to null)
27438 * @cfg {Date} maxDate
27439 * Maximum allowable date (JavaScript date object, defaults to null)
27443 * @cfg {String} minText
27444 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27446 minText : "This date is before the minimum date",
27448 * @cfg {String} maxText
27449 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27451 maxText : "This date is after the maximum date",
27453 * @cfg {String} format
27454 * The default date format string which can be overriden for localization support. The format must be
27455 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27459 * @cfg {Array} disabledDays
27460 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27462 disabledDays : null,
27464 * @cfg {String} disabledDaysText
27465 * The tooltip to display when the date falls on a disabled day (defaults to "")
27467 disabledDaysText : "",
27469 * @cfg {RegExp} disabledDatesRE
27470 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27472 disabledDatesRE : null,
27474 * @cfg {String} disabledDatesText
27475 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27477 disabledDatesText : "",
27479 * @cfg {Boolean} constrainToViewport
27480 * True to constrain the date picker to the viewport (defaults to true)
27482 constrainToViewport : true,
27484 * @cfg {Array} monthNames
27485 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27487 monthNames : Date.monthNames,
27489 * @cfg {Array} dayNames
27490 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27492 dayNames : Date.dayNames,
27494 * @cfg {String} nextText
27495 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27497 nextText: 'Next Month (Control+Right)',
27499 * @cfg {String} prevText
27500 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27502 prevText: 'Previous Month (Control+Left)',
27504 * @cfg {String} monthYearText
27505 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27507 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27509 * @cfg {Number} startDay
27510 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27514 * @cfg {Bool} showClear
27515 * Show a clear button (usefull for date form elements that can be blank.)
27521 * Sets the value of the date field
27522 * @param {Date} value The date to set
27524 setValue : function(value){
27525 var old = this.value;
27527 if (typeof(value) == 'string') {
27529 value = Date.parseDate(value, this.format);
27532 value = new Date();
27535 this.value = value.clearTime(true);
27537 this.update(this.value);
27542 * Gets the current selected value of the date field
27543 * @return {Date} The selected date
27545 getValue : function(){
27550 focus : function(){
27552 this.update(this.activeDate);
27557 onRender : function(container, position){
27560 '<table cellspacing="0">',
27561 '<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>',
27562 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27563 var dn = this.dayNames;
27564 for(var i = 0; i < 7; i++){
27565 var d = this.startDay+i;
27569 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27571 m[m.length] = "</tr></thead><tbody><tr>";
27572 for(var i = 0; i < 42; i++) {
27573 if(i % 7 == 0 && i != 0){
27574 m[m.length] = "</tr><tr>";
27576 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27578 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27579 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27581 var el = document.createElement("div");
27582 el.className = "x-date-picker";
27583 el.innerHTML = m.join("");
27585 container.dom.insertBefore(el, position);
27587 this.el = Roo.get(el);
27588 this.eventEl = Roo.get(el.firstChild);
27590 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27591 handler: this.showPrevMonth,
27593 preventDefault:true,
27597 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27598 handler: this.showNextMonth,
27600 preventDefault:true,
27604 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27606 this.monthPicker = this.el.down('div.x-date-mp');
27607 this.monthPicker.enableDisplayMode('block');
27609 var kn = new Roo.KeyNav(this.eventEl, {
27610 "left" : function(e){
27612 this.showPrevMonth() :
27613 this.update(this.activeDate.add("d", -1));
27616 "right" : function(e){
27618 this.showNextMonth() :
27619 this.update(this.activeDate.add("d", 1));
27622 "up" : function(e){
27624 this.showNextYear() :
27625 this.update(this.activeDate.add("d", -7));
27628 "down" : function(e){
27630 this.showPrevYear() :
27631 this.update(this.activeDate.add("d", 7));
27634 "pageUp" : function(e){
27635 this.showNextMonth();
27638 "pageDown" : function(e){
27639 this.showPrevMonth();
27642 "enter" : function(e){
27643 e.stopPropagation();
27650 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27652 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27654 this.el.unselectable();
27656 this.cells = this.el.select("table.x-date-inner tbody td");
27657 this.textNodes = this.el.query("table.x-date-inner tbody span");
27659 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27661 tooltip: this.monthYearText
27664 this.mbtn.on('click', this.showMonthPicker, this);
27665 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27668 var today = (new Date()).dateFormat(this.format);
27670 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27671 if (this.showClear) {
27672 baseTb.add( new Roo.Toolbar.Fill());
27675 text: String.format(this.todayText, today),
27676 tooltip: String.format(this.todayTip, today),
27677 handler: this.selectToday,
27681 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27684 if (this.showClear) {
27686 baseTb.add( new Roo.Toolbar.Fill());
27689 cls: 'x-btn-icon x-btn-clear',
27690 handler: function() {
27692 this.fireEvent("select", this, '');
27702 this.update(this.value);
27705 createMonthPicker : function(){
27706 if(!this.monthPicker.dom.firstChild){
27707 var buf = ['<table border="0" cellspacing="0">'];
27708 for(var i = 0; i < 6; i++){
27710 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27711 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27713 '<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>' :
27714 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27718 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27720 '</button><button type="button" class="x-date-mp-cancel">',
27722 '</button></td></tr>',
27725 this.monthPicker.update(buf.join(''));
27726 this.monthPicker.on('click', this.onMonthClick, this);
27727 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27729 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27730 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27732 this.mpMonths.each(function(m, a, i){
27735 m.dom.xmonth = 5 + Math.round(i * .5);
27737 m.dom.xmonth = Math.round((i-1) * .5);
27743 showMonthPicker : function(){
27744 this.createMonthPicker();
27745 var size = this.el.getSize();
27746 this.monthPicker.setSize(size);
27747 this.monthPicker.child('table').setSize(size);
27749 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27750 this.updateMPMonth(this.mpSelMonth);
27751 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27752 this.updateMPYear(this.mpSelYear);
27754 this.monthPicker.slideIn('t', {duration:.2});
27757 updateMPYear : function(y){
27759 var ys = this.mpYears.elements;
27760 for(var i = 1; i <= 10; i++){
27761 var td = ys[i-1], y2;
27763 y2 = y + Math.round(i * .5);
27764 td.firstChild.innerHTML = y2;
27767 y2 = y - (5-Math.round(i * .5));
27768 td.firstChild.innerHTML = y2;
27771 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27775 updateMPMonth : function(sm){
27776 this.mpMonths.each(function(m, a, i){
27777 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27781 selectMPMonth: function(m){
27785 onMonthClick : function(e, t){
27787 var el = new Roo.Element(t), pn;
27788 if(el.is('button.x-date-mp-cancel')){
27789 this.hideMonthPicker();
27791 else if(el.is('button.x-date-mp-ok')){
27792 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27793 this.hideMonthPicker();
27795 else if(pn = el.up('td.x-date-mp-month', 2)){
27796 this.mpMonths.removeClass('x-date-mp-sel');
27797 pn.addClass('x-date-mp-sel');
27798 this.mpSelMonth = pn.dom.xmonth;
27800 else if(pn = el.up('td.x-date-mp-year', 2)){
27801 this.mpYears.removeClass('x-date-mp-sel');
27802 pn.addClass('x-date-mp-sel');
27803 this.mpSelYear = pn.dom.xyear;
27805 else if(el.is('a.x-date-mp-prev')){
27806 this.updateMPYear(this.mpyear-10);
27808 else if(el.is('a.x-date-mp-next')){
27809 this.updateMPYear(this.mpyear+10);
27813 onMonthDblClick : function(e, t){
27815 var el = new Roo.Element(t), pn;
27816 if(pn = el.up('td.x-date-mp-month', 2)){
27817 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27818 this.hideMonthPicker();
27820 else if(pn = el.up('td.x-date-mp-year', 2)){
27821 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27822 this.hideMonthPicker();
27826 hideMonthPicker : function(disableAnim){
27827 if(this.monthPicker){
27828 if(disableAnim === true){
27829 this.monthPicker.hide();
27831 this.monthPicker.slideOut('t', {duration:.2});
27837 showPrevMonth : function(e){
27838 this.update(this.activeDate.add("mo", -1));
27842 showNextMonth : function(e){
27843 this.update(this.activeDate.add("mo", 1));
27847 showPrevYear : function(){
27848 this.update(this.activeDate.add("y", -1));
27852 showNextYear : function(){
27853 this.update(this.activeDate.add("y", 1));
27857 handleMouseWheel : function(e){
27858 var delta = e.getWheelDelta();
27860 this.showPrevMonth();
27862 } else if(delta < 0){
27863 this.showNextMonth();
27869 handleDateClick : function(e, t){
27871 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
27872 this.setValue(new Date(t.dateValue));
27873 this.fireEvent("select", this, this.value);
27878 selectToday : function(){
27879 this.setValue(new Date().clearTime());
27880 this.fireEvent("select", this, this.value);
27884 update : function(date)
27886 var vd = this.activeDate;
27887 this.activeDate = date;
27889 var t = date.getTime();
27890 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
27891 this.cells.removeClass("x-date-selected");
27892 this.cells.each(function(c){
27893 if(c.dom.firstChild.dateValue == t){
27894 c.addClass("x-date-selected");
27895 setTimeout(function(){
27896 try{c.dom.firstChild.focus();}catch(e){}
27905 var days = date.getDaysInMonth();
27906 var firstOfMonth = date.getFirstDateOfMonth();
27907 var startingPos = firstOfMonth.getDay()-this.startDay;
27909 if(startingPos <= this.startDay){
27913 var pm = date.add("mo", -1);
27914 var prevStart = pm.getDaysInMonth()-startingPos;
27916 var cells = this.cells.elements;
27917 var textEls = this.textNodes;
27918 days += startingPos;
27920 // convert everything to numbers so it's fast
27921 var day = 86400000;
27922 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
27923 var today = new Date().clearTime().getTime();
27924 var sel = date.clearTime().getTime();
27925 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
27926 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
27927 var ddMatch = this.disabledDatesRE;
27928 var ddText = this.disabledDatesText;
27929 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
27930 var ddaysText = this.disabledDaysText;
27931 var format = this.format;
27933 var setCellClass = function(cal, cell){
27935 var t = d.getTime();
27936 cell.firstChild.dateValue = t;
27938 cell.className += " x-date-today";
27939 cell.title = cal.todayText;
27942 cell.className += " x-date-selected";
27943 setTimeout(function(){
27944 try{cell.firstChild.focus();}catch(e){}
27949 cell.className = " x-date-disabled";
27950 cell.title = cal.minText;
27954 cell.className = " x-date-disabled";
27955 cell.title = cal.maxText;
27959 if(ddays.indexOf(d.getDay()) != -1){
27960 cell.title = ddaysText;
27961 cell.className = " x-date-disabled";
27964 if(ddMatch && format){
27965 var fvalue = d.dateFormat(format);
27966 if(ddMatch.test(fvalue)){
27967 cell.title = ddText.replace("%0", fvalue);
27968 cell.className = " x-date-disabled";
27974 for(; i < startingPos; i++) {
27975 textEls[i].innerHTML = (++prevStart);
27976 d.setDate(d.getDate()+1);
27977 cells[i].className = "x-date-prevday";
27978 setCellClass(this, cells[i]);
27980 for(; i < days; i++){
27981 intDay = i - startingPos + 1;
27982 textEls[i].innerHTML = (intDay);
27983 d.setDate(d.getDate()+1);
27984 cells[i].className = "x-date-active";
27985 setCellClass(this, cells[i]);
27988 for(; i < 42; i++) {
27989 textEls[i].innerHTML = (++extraDays);
27990 d.setDate(d.getDate()+1);
27991 cells[i].className = "x-date-nextday";
27992 setCellClass(this, cells[i]);
27995 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
27996 this.fireEvent('monthchange', this, date);
27998 if(!this.internalRender){
27999 var main = this.el.dom.firstChild;
28000 var w = main.offsetWidth;
28001 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28002 Roo.fly(main).setWidth(w);
28003 this.internalRender = true;
28004 // opera does not respect the auto grow header center column
28005 // then, after it gets a width opera refuses to recalculate
28006 // without a second pass
28007 if(Roo.isOpera && !this.secondPass){
28008 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28009 this.secondPass = true;
28010 this.update.defer(10, this, [date]);
28018 * Ext JS Library 1.1.1
28019 * Copyright(c) 2006-2007, Ext JS, LLC.
28021 * Originally Released Under LGPL - original licence link has changed is not relivant.
28024 * <script type="text/javascript">
28027 * @class Roo.TabPanel
28028 * @extends Roo.util.Observable
28029 * A lightweight tab container.
28033 // basic tabs 1, built from existing content
28034 var tabs = new Roo.TabPanel("tabs1");
28035 tabs.addTab("script", "View Script");
28036 tabs.addTab("markup", "View Markup");
28037 tabs.activate("script");
28039 // more advanced tabs, built from javascript
28040 var jtabs = new Roo.TabPanel("jtabs");
28041 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28043 // set up the UpdateManager
28044 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28045 var updater = tab2.getUpdateManager();
28046 updater.setDefaultUrl("ajax1.htm");
28047 tab2.on('activate', updater.refresh, updater, true);
28049 // Use setUrl for Ajax loading
28050 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28051 tab3.setUrl("ajax2.htm", null, true);
28054 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28057 jtabs.activate("jtabs-1");
28060 * Create a new TabPanel.
28061 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28062 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28064 Roo.TabPanel = function(container, config){
28066 * The container element for this TabPanel.
28067 * @type Roo.Element
28069 this.el = Roo.get(container, true);
28071 if(typeof config == "boolean"){
28072 this.tabPosition = config ? "bottom" : "top";
28074 Roo.apply(this, config);
28077 if(this.tabPosition == "bottom"){
28078 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28079 this.el.addClass("x-tabs-bottom");
28081 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28082 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28083 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28085 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28087 if(this.tabPosition != "bottom"){
28088 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28089 * @type Roo.Element
28091 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28092 this.el.addClass("x-tabs-top");
28096 this.bodyEl.setStyle("position", "relative");
28098 this.active = null;
28099 this.activateDelegate = this.activate.createDelegate(this);
28104 * Fires when the active tab changes
28105 * @param {Roo.TabPanel} this
28106 * @param {Roo.TabPanelItem} activePanel The new active tab
28110 * @event beforetabchange
28111 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28112 * @param {Roo.TabPanel} this
28113 * @param {Object} e Set cancel to true on this object to cancel the tab change
28114 * @param {Roo.TabPanelItem} tab The tab being changed to
28116 "beforetabchange" : true
28119 Roo.EventManager.onWindowResize(this.onResize, this);
28120 this.cpad = this.el.getPadding("lr");
28121 this.hiddenCount = 0;
28124 // toolbar on the tabbar support...
28125 if (this.toolbar) {
28126 var tcfg = this.toolbar;
28127 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28128 this.toolbar = new Roo.Toolbar(tcfg);
28129 if (Roo.isSafari) {
28130 var tbl = tcfg.container.child('table', true);
28131 tbl.setAttribute('width', '100%');
28138 Roo.TabPanel.superclass.constructor.call(this);
28141 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28143 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28145 tabPosition : "top",
28147 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28149 currentTabWidth : 0,
28151 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28155 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28159 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28161 preferredTabWidth : 175,
28163 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28165 resizeTabs : false,
28167 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28169 monitorResize : true,
28171 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28176 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28177 * @param {String} id The id of the div to use <b>or create</b>
28178 * @param {String} text The text for the tab
28179 * @param {String} content (optional) Content to put in the TabPanelItem body
28180 * @param {Boolean} closable (optional) True to create a close icon on the tab
28181 * @return {Roo.TabPanelItem} The created TabPanelItem
28183 addTab : function(id, text, content, closable){
28184 var item = new Roo.TabPanelItem(this, id, text, closable);
28185 this.addTabItem(item);
28187 item.setContent(content);
28193 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28194 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28195 * @return {Roo.TabPanelItem}
28197 getTab : function(id){
28198 return this.items[id];
28202 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28203 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28205 hideTab : function(id){
28206 var t = this.items[id];
28209 this.hiddenCount++;
28210 this.autoSizeTabs();
28215 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28216 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28218 unhideTab : function(id){
28219 var t = this.items[id];
28221 t.setHidden(false);
28222 this.hiddenCount--;
28223 this.autoSizeTabs();
28228 * Adds an existing {@link Roo.TabPanelItem}.
28229 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28231 addTabItem : function(item){
28232 this.items[item.id] = item;
28233 this.items.push(item);
28234 if(this.resizeTabs){
28235 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28236 this.autoSizeTabs();
28243 * Removes a {@link Roo.TabPanelItem}.
28244 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28246 removeTab : function(id){
28247 var items = this.items;
28248 var tab = items[id];
28249 if(!tab) { return; }
28250 var index = items.indexOf(tab);
28251 if(this.active == tab && items.length > 1){
28252 var newTab = this.getNextAvailable(index);
28257 this.stripEl.dom.removeChild(tab.pnode.dom);
28258 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28259 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28261 items.splice(index, 1);
28262 delete this.items[tab.id];
28263 tab.fireEvent("close", tab);
28264 tab.purgeListeners();
28265 this.autoSizeTabs();
28268 getNextAvailable : function(start){
28269 var items = this.items;
28271 // look for a next tab that will slide over to
28272 // replace the one being removed
28273 while(index < items.length){
28274 var item = items[++index];
28275 if(item && !item.isHidden()){
28279 // if one isn't found select the previous tab (on the left)
28282 var item = items[--index];
28283 if(item && !item.isHidden()){
28291 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28292 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28294 disableTab : function(id){
28295 var tab = this.items[id];
28296 if(tab && this.active != tab){
28302 * Enables a {@link Roo.TabPanelItem} that is disabled.
28303 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28305 enableTab : function(id){
28306 var tab = this.items[id];
28311 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28312 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28313 * @return {Roo.TabPanelItem} The TabPanelItem.
28315 activate : function(id){
28316 var tab = this.items[id];
28320 if(tab == this.active || tab.disabled){
28324 this.fireEvent("beforetabchange", this, e, tab);
28325 if(e.cancel !== true && !tab.disabled){
28327 this.active.hide();
28329 this.active = this.items[id];
28330 this.active.show();
28331 this.fireEvent("tabchange", this, this.active);
28337 * Gets the active {@link Roo.TabPanelItem}.
28338 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28340 getActiveTab : function(){
28341 return this.active;
28345 * Updates the tab body element to fit the height of the container element
28346 * for overflow scrolling
28347 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28349 syncHeight : function(targetHeight){
28350 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28351 var bm = this.bodyEl.getMargins();
28352 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28353 this.bodyEl.setHeight(newHeight);
28357 onResize : function(){
28358 if(this.monitorResize){
28359 this.autoSizeTabs();
28364 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28366 beginUpdate : function(){
28367 this.updating = true;
28371 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28373 endUpdate : function(){
28374 this.updating = false;
28375 this.autoSizeTabs();
28379 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28381 autoSizeTabs : function(){
28382 var count = this.items.length;
28383 var vcount = count - this.hiddenCount;
28384 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28387 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28388 var availWidth = Math.floor(w / vcount);
28389 var b = this.stripBody;
28390 if(b.getWidth() > w){
28391 var tabs = this.items;
28392 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28393 if(availWidth < this.minTabWidth){
28394 /*if(!this.sleft){ // incomplete scrolling code
28395 this.createScrollButtons();
28398 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28401 if(this.currentTabWidth < this.preferredTabWidth){
28402 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28408 * Returns the number of tabs in this TabPanel.
28411 getCount : function(){
28412 return this.items.length;
28416 * Resizes all the tabs to the passed width
28417 * @param {Number} The new width
28419 setTabWidth : function(width){
28420 this.currentTabWidth = width;
28421 for(var i = 0, len = this.items.length; i < len; i++) {
28422 if(!this.items[i].isHidden()) {
28423 this.items[i].setWidth(width);
28429 * Destroys this TabPanel
28430 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28432 destroy : function(removeEl){
28433 Roo.EventManager.removeResizeListener(this.onResize, this);
28434 for(var i = 0, len = this.items.length; i < len; i++){
28435 this.items[i].purgeListeners();
28437 if(removeEl === true){
28438 this.el.update("");
28445 * @class Roo.TabPanelItem
28446 * @extends Roo.util.Observable
28447 * Represents an individual item (tab plus body) in a TabPanel.
28448 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28449 * @param {String} id The id of this TabPanelItem
28450 * @param {String} text The text for the tab of this TabPanelItem
28451 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28453 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28455 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28456 * @type Roo.TabPanel
28458 this.tabPanel = tabPanel;
28460 * The id for this TabPanelItem
28465 this.disabled = false;
28469 this.loaded = false;
28470 this.closable = closable;
28473 * The body element for this TabPanelItem.
28474 * @type Roo.Element
28476 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28477 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28478 this.bodyEl.setStyle("display", "block");
28479 this.bodyEl.setStyle("zoom", "1");
28482 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28484 this.el = Roo.get(els.el, true);
28485 this.inner = Roo.get(els.inner, true);
28486 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28487 this.pnode = Roo.get(els.el.parentNode, true);
28488 this.el.on("mousedown", this.onTabMouseDown, this);
28489 this.el.on("click", this.onTabClick, this);
28492 var c = Roo.get(els.close, true);
28493 c.dom.title = this.closeText;
28494 c.addClassOnOver("close-over");
28495 c.on("click", this.closeClick, this);
28501 * Fires when this tab becomes the active tab.
28502 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28503 * @param {Roo.TabPanelItem} this
28507 * @event beforeclose
28508 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28509 * @param {Roo.TabPanelItem} this
28510 * @param {Object} e Set cancel to true on this object to cancel the close.
28512 "beforeclose": true,
28515 * Fires when this tab is closed.
28516 * @param {Roo.TabPanelItem} this
28520 * @event deactivate
28521 * Fires when this tab is no longer the active tab.
28522 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28523 * @param {Roo.TabPanelItem} this
28525 "deactivate" : true
28527 this.hidden = false;
28529 Roo.TabPanelItem.superclass.constructor.call(this);
28532 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28533 purgeListeners : function(){
28534 Roo.util.Observable.prototype.purgeListeners.call(this);
28535 this.el.removeAllListeners();
28538 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28541 this.pnode.addClass("on");
28544 this.tabPanel.stripWrap.repaint();
28546 this.fireEvent("activate", this.tabPanel, this);
28550 * Returns true if this tab is the active tab.
28551 * @return {Boolean}
28553 isActive : function(){
28554 return this.tabPanel.getActiveTab() == this;
28558 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28561 this.pnode.removeClass("on");
28563 this.fireEvent("deactivate", this.tabPanel, this);
28566 hideAction : function(){
28567 this.bodyEl.hide();
28568 this.bodyEl.setStyle("position", "absolute");
28569 this.bodyEl.setLeft("-20000px");
28570 this.bodyEl.setTop("-20000px");
28573 showAction : function(){
28574 this.bodyEl.setStyle("position", "relative");
28575 this.bodyEl.setTop("");
28576 this.bodyEl.setLeft("");
28577 this.bodyEl.show();
28581 * Set the tooltip for the tab.
28582 * @param {String} tooltip The tab's tooltip
28584 setTooltip : function(text){
28585 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28586 this.textEl.dom.qtip = text;
28587 this.textEl.dom.removeAttribute('title');
28589 this.textEl.dom.title = text;
28593 onTabClick : function(e){
28594 e.preventDefault();
28595 this.tabPanel.activate(this.id);
28598 onTabMouseDown : function(e){
28599 e.preventDefault();
28600 this.tabPanel.activate(this.id);
28603 getWidth : function(){
28604 return this.inner.getWidth();
28607 setWidth : function(width){
28608 var iwidth = width - this.pnode.getPadding("lr");
28609 this.inner.setWidth(iwidth);
28610 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28611 this.pnode.setWidth(width);
28615 * Show or hide the tab
28616 * @param {Boolean} hidden True to hide or false to show.
28618 setHidden : function(hidden){
28619 this.hidden = hidden;
28620 this.pnode.setStyle("display", hidden ? "none" : "");
28624 * Returns true if this tab is "hidden"
28625 * @return {Boolean}
28627 isHidden : function(){
28628 return this.hidden;
28632 * Returns the text for this tab
28635 getText : function(){
28639 autoSize : function(){
28640 //this.el.beginMeasure();
28641 this.textEl.setWidth(1);
28643 * #2804 [new] Tabs in Roojs
28644 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28646 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28647 //this.el.endMeasure();
28651 * Sets the text for the tab (Note: this also sets the tooltip text)
28652 * @param {String} text The tab's text and tooltip
28654 setText : function(text){
28656 this.textEl.update(text);
28657 this.setTooltip(text);
28658 if(!this.tabPanel.resizeTabs){
28663 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28665 activate : function(){
28666 this.tabPanel.activate(this.id);
28670 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28672 disable : function(){
28673 if(this.tabPanel.active != this){
28674 this.disabled = true;
28675 this.pnode.addClass("disabled");
28680 * Enables this TabPanelItem if it was previously disabled.
28682 enable : function(){
28683 this.disabled = false;
28684 this.pnode.removeClass("disabled");
28688 * Sets the content for this TabPanelItem.
28689 * @param {String} content The content
28690 * @param {Boolean} loadScripts true to look for and load scripts
28692 setContent : function(content, loadScripts){
28693 this.bodyEl.update(content, loadScripts);
28697 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28698 * @return {Roo.UpdateManager} The UpdateManager
28700 getUpdateManager : function(){
28701 return this.bodyEl.getUpdateManager();
28705 * Set a URL to be used to load the content for this TabPanelItem.
28706 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28707 * @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)
28708 * @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)
28709 * @return {Roo.UpdateManager} The UpdateManager
28711 setUrl : function(url, params, loadOnce){
28712 if(this.refreshDelegate){
28713 this.un('activate', this.refreshDelegate);
28715 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28716 this.on("activate", this.refreshDelegate);
28717 return this.bodyEl.getUpdateManager();
28721 _handleRefresh : function(url, params, loadOnce){
28722 if(!loadOnce || !this.loaded){
28723 var updater = this.bodyEl.getUpdateManager();
28724 updater.update(url, params, this._setLoaded.createDelegate(this));
28729 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28730 * Will fail silently if the setUrl method has not been called.
28731 * This does not activate the panel, just updates its content.
28733 refresh : function(){
28734 if(this.refreshDelegate){
28735 this.loaded = false;
28736 this.refreshDelegate();
28741 _setLoaded : function(){
28742 this.loaded = true;
28746 closeClick : function(e){
28749 this.fireEvent("beforeclose", this, o);
28750 if(o.cancel !== true){
28751 this.tabPanel.removeTab(this.id);
28755 * The text displayed in the tooltip for the close icon.
28758 closeText : "Close this tab"
28762 Roo.TabPanel.prototype.createStrip = function(container){
28763 var strip = document.createElement("div");
28764 strip.className = "x-tabs-wrap";
28765 container.appendChild(strip);
28769 Roo.TabPanel.prototype.createStripList = function(strip){
28770 // div wrapper for retard IE
28771 // returns the "tr" element.
28772 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28773 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28774 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28775 return strip.firstChild.firstChild.firstChild.firstChild;
28778 Roo.TabPanel.prototype.createBody = function(container){
28779 var body = document.createElement("div");
28780 Roo.id(body, "tab-body");
28781 Roo.fly(body).addClass("x-tabs-body");
28782 container.appendChild(body);
28786 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28787 var body = Roo.getDom(id);
28789 body = document.createElement("div");
28792 Roo.fly(body).addClass("x-tabs-item-body");
28793 bodyEl.insertBefore(body, bodyEl.firstChild);
28797 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28798 var td = document.createElement("td");
28799 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28800 //stripEl.appendChild(td);
28802 td.className = "x-tabs-closable";
28803 if(!this.closeTpl){
28804 this.closeTpl = new Roo.Template(
28805 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28806 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28807 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28810 var el = this.closeTpl.overwrite(td, {"text": text});
28811 var close = el.getElementsByTagName("div")[0];
28812 var inner = el.getElementsByTagName("em")[0];
28813 return {"el": el, "close": close, "inner": inner};
28816 this.tabTpl = new Roo.Template(
28817 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28818 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28821 var el = this.tabTpl.overwrite(td, {"text": text});
28822 var inner = el.getElementsByTagName("em")[0];
28823 return {"el": el, "inner": inner};
28827 * Ext JS Library 1.1.1
28828 * Copyright(c) 2006-2007, Ext JS, LLC.
28830 * Originally Released Under LGPL - original licence link has changed is not relivant.
28833 * <script type="text/javascript">
28837 * @class Roo.Button
28838 * @extends Roo.util.Observable
28839 * Simple Button class
28840 * @cfg {String} text The button text
28841 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28842 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28843 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28844 * @cfg {Object} scope The scope of the handler
28845 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28846 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
28847 * @cfg {Boolean} hidden True to start hidden (defaults to false)
28848 * @cfg {Boolean} disabled True to start disabled (defaults to false)
28849 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
28850 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
28851 applies if enableToggle = true)
28852 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
28853 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28854 an {@link Roo.util.ClickRepeater} config object (defaults to false).
28856 * Create a new button
28857 * @param {Object} config The config object
28859 Roo.Button = function(renderTo, config)
28863 renderTo = config.renderTo || false;
28866 Roo.apply(this, config);
28870 * Fires when this button is clicked
28871 * @param {Button} this
28872 * @param {EventObject} e The click event
28877 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
28878 * @param {Button} this
28879 * @param {Boolean} pressed
28884 * Fires when the mouse hovers over the button
28885 * @param {Button} this
28886 * @param {Event} e The event object
28888 'mouseover' : true,
28891 * Fires when the mouse exits the button
28892 * @param {Button} this
28893 * @param {Event} e The event object
28898 * Fires when the button is rendered
28899 * @param {Button} this
28904 this.menu = Roo.menu.MenuMgr.get(this.menu);
28906 // register listeners first!! - so render can be captured..
28907 Roo.util.Observable.call(this);
28909 this.render(renderTo);
28915 Roo.extend(Roo.Button, Roo.util.Observable, {
28921 * Read-only. True if this button is hidden
28926 * Read-only. True if this button is disabled
28931 * Read-only. True if this button is pressed (only if enableToggle = true)
28937 * @cfg {Number} tabIndex
28938 * The DOM tabIndex for this button (defaults to undefined)
28940 tabIndex : undefined,
28943 * @cfg {Boolean} enableToggle
28944 * True to enable pressed/not pressed toggling (defaults to false)
28946 enableToggle: false,
28948 * @cfg {Mixed} menu
28949 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
28953 * @cfg {String} menuAlign
28954 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
28956 menuAlign : "tl-bl?",
28959 * @cfg {String} iconCls
28960 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
28962 iconCls : undefined,
28964 * @cfg {String} type
28965 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
28970 menuClassTarget: 'tr',
28973 * @cfg {String} clickEvent
28974 * The type of event to map to the button's event handler (defaults to 'click')
28976 clickEvent : 'click',
28979 * @cfg {Boolean} handleMouseEvents
28980 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
28982 handleMouseEvents : true,
28985 * @cfg {String} tooltipType
28986 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
28988 tooltipType : 'qtip',
28991 * @cfg {String} cls
28992 * A CSS class to apply to the button's main element.
28996 * @cfg {Roo.Template} template (Optional)
28997 * An {@link Roo.Template} with which to create the Button's main element. This Template must
28998 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
28999 * require code modifications if required elements (e.g. a button) aren't present.
29003 render : function(renderTo){
29005 if(this.hideParent){
29006 this.parentEl = Roo.get(renderTo);
29008 if(!this.dhconfig){
29009 if(!this.template){
29010 if(!Roo.Button.buttonTemplate){
29011 // hideous table template
29012 Roo.Button.buttonTemplate = new Roo.Template(
29013 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29014 '<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>',
29015 "</tr></tbody></table>");
29017 this.template = Roo.Button.buttonTemplate;
29019 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29020 var btnEl = btn.child("button:first");
29021 btnEl.on('focus', this.onFocus, this);
29022 btnEl.on('blur', this.onBlur, this);
29024 btn.addClass(this.cls);
29027 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29030 btnEl.addClass(this.iconCls);
29032 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29035 if(this.tabIndex !== undefined){
29036 btnEl.dom.tabIndex = this.tabIndex;
29039 if(typeof this.tooltip == 'object'){
29040 Roo.QuickTips.tips(Roo.apply({
29044 btnEl.dom[this.tooltipType] = this.tooltip;
29048 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29052 this.el.dom.id = this.el.id = this.id;
29055 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29056 this.menu.on("show", this.onMenuShow, this);
29057 this.menu.on("hide", this.onMenuHide, this);
29059 btn.addClass("x-btn");
29060 if(Roo.isIE && !Roo.isIE7){
29061 this.autoWidth.defer(1, this);
29065 if(this.handleMouseEvents){
29066 btn.on("mouseover", this.onMouseOver, this);
29067 btn.on("mouseout", this.onMouseOut, this);
29068 btn.on("mousedown", this.onMouseDown, this);
29070 btn.on(this.clickEvent, this.onClick, this);
29071 //btn.on("mouseup", this.onMouseUp, this);
29078 Roo.ButtonToggleMgr.register(this);
29080 this.el.addClass("x-btn-pressed");
29083 var repeater = new Roo.util.ClickRepeater(btn,
29084 typeof this.repeat == "object" ? this.repeat : {}
29086 repeater.on("click", this.onClick, this);
29089 this.fireEvent('render', this);
29093 * Returns the button's underlying element
29094 * @return {Roo.Element} The element
29096 getEl : function(){
29101 * Destroys this Button and removes any listeners.
29103 destroy : function(){
29104 Roo.ButtonToggleMgr.unregister(this);
29105 this.el.removeAllListeners();
29106 this.purgeListeners();
29111 autoWidth : function(){
29113 this.el.setWidth("auto");
29114 if(Roo.isIE7 && Roo.isStrict){
29115 var ib = this.el.child('button');
29116 if(ib && ib.getWidth() > 20){
29118 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29123 this.el.beginMeasure();
29125 if(this.el.getWidth() < this.minWidth){
29126 this.el.setWidth(this.minWidth);
29129 this.el.endMeasure();
29136 * Assigns this button's click handler
29137 * @param {Function} handler The function to call when the button is clicked
29138 * @param {Object} scope (optional) Scope for the function passed in
29140 setHandler : function(handler, scope){
29141 this.handler = handler;
29142 this.scope = scope;
29146 * Sets this button's text
29147 * @param {String} text The button text
29149 setText : function(text){
29152 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29158 * Gets the text for this button
29159 * @return {String} The button text
29161 getText : function(){
29169 this.hidden = false;
29171 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29179 this.hidden = true;
29181 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29186 * Convenience function for boolean show/hide
29187 * @param {Boolean} visible True to show, false to hide
29189 setVisible: function(visible){
29198 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29199 * @param {Boolean} state (optional) Force a particular state
29201 toggle : function(state){
29202 state = state === undefined ? !this.pressed : state;
29203 if(state != this.pressed){
29205 this.el.addClass("x-btn-pressed");
29206 this.pressed = true;
29207 this.fireEvent("toggle", this, true);
29209 this.el.removeClass("x-btn-pressed");
29210 this.pressed = false;
29211 this.fireEvent("toggle", this, false);
29213 if(this.toggleHandler){
29214 this.toggleHandler.call(this.scope || this, this, state);
29222 focus : function(){
29223 this.el.child('button:first').focus();
29227 * Disable this button
29229 disable : function(){
29231 this.el.addClass("x-btn-disabled");
29233 this.disabled = true;
29237 * Enable this button
29239 enable : function(){
29241 this.el.removeClass("x-btn-disabled");
29243 this.disabled = false;
29247 * Convenience function for boolean enable/disable
29248 * @param {Boolean} enabled True to enable, false to disable
29250 setDisabled : function(v){
29251 this[v !== true ? "enable" : "disable"]();
29255 onClick : function(e)
29258 e.preventDefault();
29263 if(!this.disabled){
29264 if(this.enableToggle){
29267 if(this.menu && !this.menu.isVisible()){
29268 this.menu.show(this.el, this.menuAlign);
29270 this.fireEvent("click", this, e);
29272 this.el.removeClass("x-btn-over");
29273 this.handler.call(this.scope || this, this, e);
29278 onMouseOver : function(e){
29279 if(!this.disabled){
29280 this.el.addClass("x-btn-over");
29281 this.fireEvent('mouseover', this, e);
29285 onMouseOut : function(e){
29286 if(!e.within(this.el, true)){
29287 this.el.removeClass("x-btn-over");
29288 this.fireEvent('mouseout', this, e);
29292 onFocus : function(e){
29293 if(!this.disabled){
29294 this.el.addClass("x-btn-focus");
29298 onBlur : function(e){
29299 this.el.removeClass("x-btn-focus");
29302 onMouseDown : function(e){
29303 if(!this.disabled && e.button == 0){
29304 this.el.addClass("x-btn-click");
29305 Roo.get(document).on('mouseup', this.onMouseUp, this);
29309 onMouseUp : function(e){
29311 this.el.removeClass("x-btn-click");
29312 Roo.get(document).un('mouseup', this.onMouseUp, this);
29316 onMenuShow : function(e){
29317 this.el.addClass("x-btn-menu-active");
29320 onMenuHide : function(e){
29321 this.el.removeClass("x-btn-menu-active");
29325 // Private utility class used by Button
29326 Roo.ButtonToggleMgr = function(){
29329 function toggleGroup(btn, state){
29331 var g = groups[btn.toggleGroup];
29332 for(var i = 0, l = g.length; i < l; i++){
29334 g[i].toggle(false);
29341 register : function(btn){
29342 if(!btn.toggleGroup){
29345 var g = groups[btn.toggleGroup];
29347 g = groups[btn.toggleGroup] = [];
29350 btn.on("toggle", toggleGroup);
29353 unregister : function(btn){
29354 if(!btn.toggleGroup){
29357 var g = groups[btn.toggleGroup];
29360 btn.un("toggle", toggleGroup);
29366 * Ext JS Library 1.1.1
29367 * Copyright(c) 2006-2007, Ext JS, LLC.
29369 * Originally Released Under LGPL - original licence link has changed is not relivant.
29372 * <script type="text/javascript">
29376 * @class Roo.SplitButton
29377 * @extends Roo.Button
29378 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29379 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29380 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29381 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29382 * @cfg {String} arrowTooltip The title attribute of the arrow
29384 * Create a new menu button
29385 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29386 * @param {Object} config The config object
29388 Roo.SplitButton = function(renderTo, config){
29389 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29391 * @event arrowclick
29392 * Fires when this button's arrow is clicked
29393 * @param {SplitButton} this
29394 * @param {EventObject} e The click event
29396 this.addEvents({"arrowclick":true});
29399 Roo.extend(Roo.SplitButton, Roo.Button, {
29400 render : function(renderTo){
29401 // this is one sweet looking template!
29402 var tpl = new Roo.Template(
29403 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29404 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29405 '<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>',
29406 "</tbody></table></td><td>",
29407 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29408 '<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>',
29409 "</tbody></table></td></tr></table>"
29411 var btn = tpl.append(renderTo, [this.text, this.type], true);
29412 var btnEl = btn.child("button");
29414 btn.addClass(this.cls);
29417 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29420 btnEl.addClass(this.iconCls);
29422 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29426 if(this.handleMouseEvents){
29427 btn.on("mouseover", this.onMouseOver, this);
29428 btn.on("mouseout", this.onMouseOut, this);
29429 btn.on("mousedown", this.onMouseDown, this);
29430 btn.on("mouseup", this.onMouseUp, this);
29432 btn.on(this.clickEvent, this.onClick, this);
29434 if(typeof this.tooltip == 'object'){
29435 Roo.QuickTips.tips(Roo.apply({
29439 btnEl.dom[this.tooltipType] = this.tooltip;
29442 if(this.arrowTooltip){
29443 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29452 this.el.addClass("x-btn-pressed");
29454 if(Roo.isIE && !Roo.isIE7){
29455 this.autoWidth.defer(1, this);
29460 this.menu.on("show", this.onMenuShow, this);
29461 this.menu.on("hide", this.onMenuHide, this);
29463 this.fireEvent('render', this);
29467 autoWidth : function(){
29469 var tbl = this.el.child("table:first");
29470 var tbl2 = this.el.child("table:last");
29471 this.el.setWidth("auto");
29472 tbl.setWidth("auto");
29473 if(Roo.isIE7 && Roo.isStrict){
29474 var ib = this.el.child('button:first');
29475 if(ib && ib.getWidth() > 20){
29477 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29482 this.el.beginMeasure();
29484 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29485 tbl.setWidth(this.minWidth-tbl2.getWidth());
29488 this.el.endMeasure();
29491 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29495 * Sets this button's click handler
29496 * @param {Function} handler The function to call when the button is clicked
29497 * @param {Object} scope (optional) Scope for the function passed above
29499 setHandler : function(handler, scope){
29500 this.handler = handler;
29501 this.scope = scope;
29505 * Sets this button's arrow click handler
29506 * @param {Function} handler The function to call when the arrow is clicked
29507 * @param {Object} scope (optional) Scope for the function passed above
29509 setArrowHandler : function(handler, scope){
29510 this.arrowHandler = handler;
29511 this.scope = scope;
29517 focus : function(){
29519 this.el.child("button:first").focus();
29524 onClick : function(e){
29525 e.preventDefault();
29526 if(!this.disabled){
29527 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29528 if(this.menu && !this.menu.isVisible()){
29529 this.menu.show(this.el, this.menuAlign);
29531 this.fireEvent("arrowclick", this, e);
29532 if(this.arrowHandler){
29533 this.arrowHandler.call(this.scope || this, this, e);
29536 this.fireEvent("click", this, e);
29538 this.handler.call(this.scope || this, this, e);
29544 onMouseDown : function(e){
29545 if(!this.disabled){
29546 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29550 onMouseUp : function(e){
29551 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29556 // backwards compat
29557 Roo.MenuButton = Roo.SplitButton;/*
29559 * Ext JS Library 1.1.1
29560 * Copyright(c) 2006-2007, Ext JS, LLC.
29562 * Originally Released Under LGPL - original licence link has changed is not relivant.
29565 * <script type="text/javascript">
29569 * @class Roo.Toolbar
29570 * Basic Toolbar class.
29572 * Creates a new Toolbar
29573 * @param {Object} container The config object
29575 Roo.Toolbar = function(container, buttons, config)
29577 /// old consturctor format still supported..
29578 if(container instanceof Array){ // omit the container for later rendering
29579 buttons = container;
29583 if (typeof(container) == 'object' && container.xtype) {
29584 config = container;
29585 container = config.container;
29586 buttons = config.buttons || []; // not really - use items!!
29589 if (config && config.items) {
29590 xitems = config.items;
29591 delete config.items;
29593 Roo.apply(this, config);
29594 this.buttons = buttons;
29597 this.render(container);
29599 this.xitems = xitems;
29600 Roo.each(xitems, function(b) {
29606 Roo.Toolbar.prototype = {
29608 * @cfg {Array} items
29609 * array of button configs or elements to add (will be converted to a MixedCollection)
29613 * @cfg {String/HTMLElement/Element} container
29614 * The id or element that will contain the toolbar
29617 render : function(ct){
29618 this.el = Roo.get(ct);
29620 this.el.addClass(this.cls);
29622 // using a table allows for vertical alignment
29623 // 100% width is needed by Safari...
29624 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29625 this.tr = this.el.child("tr", true);
29627 this.items = new Roo.util.MixedCollection(false, function(o){
29628 return o.id || ("item" + (++autoId));
29631 this.add.apply(this, this.buttons);
29632 delete this.buttons;
29637 * Adds element(s) to the toolbar -- this function takes a variable number of
29638 * arguments of mixed type and adds them to the toolbar.
29639 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29641 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29642 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29643 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29644 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29645 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29646 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29647 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29648 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29649 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29651 * @param {Mixed} arg2
29652 * @param {Mixed} etc.
29655 var a = arguments, l = a.length;
29656 for(var i = 0; i < l; i++){
29661 _add : function(el) {
29664 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29667 if (el.applyTo){ // some kind of form field
29668 return this.addField(el);
29670 if (el.render){ // some kind of Toolbar.Item
29671 return this.addItem(el);
29673 if (typeof el == "string"){ // string
29674 if(el == "separator" || el == "-"){
29675 return this.addSeparator();
29678 return this.addSpacer();
29681 return this.addFill();
29683 return this.addText(el);
29686 if(el.tagName){ // element
29687 return this.addElement(el);
29689 if(typeof el == "object"){ // must be button config?
29690 return this.addButton(el);
29692 // and now what?!?!
29698 * Add an Xtype element
29699 * @param {Object} xtype Xtype Object
29700 * @return {Object} created Object
29702 addxtype : function(e){
29703 return this.add(e);
29707 * Returns the Element for this toolbar.
29708 * @return {Roo.Element}
29710 getEl : function(){
29716 * @return {Roo.Toolbar.Item} The separator item
29718 addSeparator : function(){
29719 return this.addItem(new Roo.Toolbar.Separator());
29723 * Adds a spacer element
29724 * @return {Roo.Toolbar.Spacer} The spacer item
29726 addSpacer : function(){
29727 return this.addItem(new Roo.Toolbar.Spacer());
29731 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29732 * @return {Roo.Toolbar.Fill} The fill item
29734 addFill : function(){
29735 return this.addItem(new Roo.Toolbar.Fill());
29739 * Adds any standard HTML element to the toolbar
29740 * @param {String/HTMLElement/Element} el The element or id of the element to add
29741 * @return {Roo.Toolbar.Item} The element's item
29743 addElement : function(el){
29744 return this.addItem(new Roo.Toolbar.Item(el));
29747 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29748 * @type Roo.util.MixedCollection
29753 * Adds any Toolbar.Item or subclass
29754 * @param {Roo.Toolbar.Item} item
29755 * @return {Roo.Toolbar.Item} The item
29757 addItem : function(item){
29758 var td = this.nextBlock();
29760 this.items.add(item);
29765 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29766 * @param {Object/Array} config A button config or array of configs
29767 * @return {Roo.Toolbar.Button/Array}
29769 addButton : function(config){
29770 if(config instanceof Array){
29772 for(var i = 0, len = config.length; i < len; i++) {
29773 buttons.push(this.addButton(config[i]));
29778 if(!(config instanceof Roo.Toolbar.Button)){
29780 new Roo.Toolbar.SplitButton(config) :
29781 new Roo.Toolbar.Button(config);
29783 var td = this.nextBlock();
29790 * Adds text to the toolbar
29791 * @param {String} text The text to add
29792 * @return {Roo.Toolbar.Item} The element's item
29794 addText : function(text){
29795 return this.addItem(new Roo.Toolbar.TextItem(text));
29799 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29800 * @param {Number} index The index where the item is to be inserted
29801 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29802 * @return {Roo.Toolbar.Button/Item}
29804 insertButton : function(index, item){
29805 if(item instanceof Array){
29807 for(var i = 0, len = item.length; i < len; i++) {
29808 buttons.push(this.insertButton(index + i, item[i]));
29812 if (!(item instanceof Roo.Toolbar.Button)){
29813 item = new Roo.Toolbar.Button(item);
29815 var td = document.createElement("td");
29816 this.tr.insertBefore(td, this.tr.childNodes[index]);
29818 this.items.insert(index, item);
29823 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29824 * @param {Object} config
29825 * @return {Roo.Toolbar.Item} The element's item
29827 addDom : function(config, returnEl){
29828 var td = this.nextBlock();
29829 Roo.DomHelper.overwrite(td, config);
29830 var ti = new Roo.Toolbar.Item(td.firstChild);
29832 this.items.add(ti);
29837 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29838 * @type Roo.util.MixedCollection
29843 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29844 * Note: the field should not have been rendered yet. For a field that has already been
29845 * rendered, use {@link #addElement}.
29846 * @param {Roo.form.Field} field
29847 * @return {Roo.ToolbarItem}
29851 addField : function(field) {
29852 if (!this.fields) {
29854 this.fields = new Roo.util.MixedCollection(false, function(o){
29855 return o.id || ("item" + (++autoId));
29860 var td = this.nextBlock();
29862 var ti = new Roo.Toolbar.Item(td.firstChild);
29864 this.items.add(ti);
29865 this.fields.add(field);
29876 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
29877 this.el.child('div').hide();
29885 this.el.child('div').show();
29889 nextBlock : function(){
29890 var td = document.createElement("td");
29891 this.tr.appendChild(td);
29896 destroy : function(){
29897 if(this.items){ // rendered?
29898 Roo.destroy.apply(Roo, this.items.items);
29900 if(this.fields){ // rendered?
29901 Roo.destroy.apply(Roo, this.fields.items);
29903 Roo.Element.uncache(this.el, this.tr);
29908 * @class Roo.Toolbar.Item
29909 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
29911 * Creates a new Item
29912 * @param {HTMLElement} el
29914 Roo.Toolbar.Item = function(el){
29916 if (typeof (el.xtype) != 'undefined') {
29921 this.el = Roo.getDom(el);
29922 this.id = Roo.id(this.el);
29923 this.hidden = false;
29928 * Fires when the button is rendered
29929 * @param {Button} this
29933 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
29935 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
29936 //Roo.Toolbar.Item.prototype = {
29939 * Get this item's HTML Element
29940 * @return {HTMLElement}
29942 getEl : function(){
29947 render : function(td){
29950 td.appendChild(this.el);
29952 this.fireEvent('render', this);
29956 * Removes and destroys this item.
29958 destroy : function(){
29959 this.td.parentNode.removeChild(this.td);
29966 this.hidden = false;
29967 this.td.style.display = "";
29974 this.hidden = true;
29975 this.td.style.display = "none";
29979 * Convenience function for boolean show/hide.
29980 * @param {Boolean} visible true to show/false to hide
29982 setVisible: function(visible){
29991 * Try to focus this item.
29993 focus : function(){
29994 Roo.fly(this.el).focus();
29998 * Disables this item.
30000 disable : function(){
30001 Roo.fly(this.td).addClass("x-item-disabled");
30002 this.disabled = true;
30003 this.el.disabled = true;
30007 * Enables this item.
30009 enable : function(){
30010 Roo.fly(this.td).removeClass("x-item-disabled");
30011 this.disabled = false;
30012 this.el.disabled = false;
30018 * @class Roo.Toolbar.Separator
30019 * @extends Roo.Toolbar.Item
30020 * A simple toolbar separator class
30022 * Creates a new Separator
30024 Roo.Toolbar.Separator = function(cfg){
30026 var s = document.createElement("span");
30027 s.className = "ytb-sep";
30032 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30034 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30035 enable:Roo.emptyFn,
30036 disable:Roo.emptyFn,
30041 * @class Roo.Toolbar.Spacer
30042 * @extends Roo.Toolbar.Item
30043 * A simple element that adds extra horizontal space to a toolbar.
30045 * Creates a new Spacer
30047 Roo.Toolbar.Spacer = function(cfg){
30048 var s = document.createElement("div");
30049 s.className = "ytb-spacer";
30053 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30055 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30056 enable:Roo.emptyFn,
30057 disable:Roo.emptyFn,
30062 * @class Roo.Toolbar.Fill
30063 * @extends Roo.Toolbar.Spacer
30064 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30066 * Creates a new Spacer
30068 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30070 render : function(td){
30071 td.style.width = '100%';
30072 Roo.Toolbar.Fill.superclass.render.call(this, td);
30077 * @class Roo.Toolbar.TextItem
30078 * @extends Roo.Toolbar.Item
30079 * A simple class that renders text directly into a toolbar.
30081 * Creates a new TextItem
30082 * @param {String} text
30084 Roo.Toolbar.TextItem = function(cfg){
30085 var text = cfg || "";
30086 if (typeof(cfg) == 'object') {
30087 text = cfg.text || "";
30091 var s = document.createElement("span");
30092 s.className = "ytb-text";
30093 s.innerHTML = text;
30098 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30100 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30103 enable:Roo.emptyFn,
30104 disable:Roo.emptyFn,
30109 * @class Roo.Toolbar.Button
30110 * @extends Roo.Button
30111 * A button that renders into a toolbar.
30113 * Creates a new Button
30114 * @param {Object} config A standard {@link Roo.Button} config object
30116 Roo.Toolbar.Button = function(config){
30117 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30119 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30120 render : function(td){
30122 Roo.Toolbar.Button.superclass.render.call(this, td);
30126 * Removes and destroys this button
30128 destroy : function(){
30129 Roo.Toolbar.Button.superclass.destroy.call(this);
30130 this.td.parentNode.removeChild(this.td);
30134 * Shows this button
30137 this.hidden = false;
30138 this.td.style.display = "";
30142 * Hides this button
30145 this.hidden = true;
30146 this.td.style.display = "none";
30150 * Disables this item
30152 disable : function(){
30153 Roo.fly(this.td).addClass("x-item-disabled");
30154 this.disabled = true;
30158 * Enables this item
30160 enable : function(){
30161 Roo.fly(this.td).removeClass("x-item-disabled");
30162 this.disabled = false;
30165 // backwards compat
30166 Roo.ToolbarButton = Roo.Toolbar.Button;
30169 * @class Roo.Toolbar.SplitButton
30170 * @extends Roo.SplitButton
30171 * A menu button that renders into a toolbar.
30173 * Creates a new SplitButton
30174 * @param {Object} config A standard {@link Roo.SplitButton} config object
30176 Roo.Toolbar.SplitButton = function(config){
30177 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30179 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30180 render : function(td){
30182 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30186 * Removes and destroys this button
30188 destroy : function(){
30189 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30190 this.td.parentNode.removeChild(this.td);
30194 * Shows this button
30197 this.hidden = false;
30198 this.td.style.display = "";
30202 * Hides this button
30205 this.hidden = true;
30206 this.td.style.display = "none";
30210 // backwards compat
30211 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30213 * Ext JS Library 1.1.1
30214 * Copyright(c) 2006-2007, Ext JS, LLC.
30216 * Originally Released Under LGPL - original licence link has changed is not relivant.
30219 * <script type="text/javascript">
30223 * @class Roo.PagingToolbar
30224 * @extends Roo.Toolbar
30225 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30227 * Create a new PagingToolbar
30228 * @param {Object} config The config object
30230 Roo.PagingToolbar = function(el, ds, config)
30232 // old args format still supported... - xtype is prefered..
30233 if (typeof(el) == 'object' && el.xtype) {
30234 // created from xtype...
30236 ds = el.dataSource;
30237 el = config.container;
30240 if (config.items) {
30241 items = config.items;
30245 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30248 this.renderButtons(this.el);
30251 // supprot items array.
30253 Roo.each(items, function(e) {
30254 this.add(Roo.factory(e));
30259 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30261 * @cfg {Roo.data.Store} dataSource
30262 * The underlying data store providing the paged data
30265 * @cfg {String/HTMLElement/Element} container
30266 * container The id or element that will contain the toolbar
30269 * @cfg {Boolean} displayInfo
30270 * True to display the displayMsg (defaults to false)
30273 * @cfg {Number} pageSize
30274 * The number of records to display per page (defaults to 20)
30278 * @cfg {String} displayMsg
30279 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30281 displayMsg : 'Displaying {0} - {1} of {2}',
30283 * @cfg {String} emptyMsg
30284 * The message to display when no records are found (defaults to "No data to display")
30286 emptyMsg : 'No data to display',
30288 * Customizable piece of the default paging text (defaults to "Page")
30291 beforePageText : "Page",
30293 * Customizable piece of the default paging text (defaults to "of %0")
30296 afterPageText : "of {0}",
30298 * Customizable piece of the default paging text (defaults to "First Page")
30301 firstText : "First Page",
30303 * Customizable piece of the default paging text (defaults to "Previous Page")
30306 prevText : "Previous Page",
30308 * Customizable piece of the default paging text (defaults to "Next Page")
30311 nextText : "Next Page",
30313 * Customizable piece of the default paging text (defaults to "Last Page")
30316 lastText : "Last Page",
30318 * Customizable piece of the default paging text (defaults to "Refresh")
30321 refreshText : "Refresh",
30324 renderButtons : function(el){
30325 Roo.PagingToolbar.superclass.render.call(this, el);
30326 this.first = this.addButton({
30327 tooltip: this.firstText,
30328 cls: "x-btn-icon x-grid-page-first",
30330 handler: this.onClick.createDelegate(this, ["first"])
30332 this.prev = this.addButton({
30333 tooltip: this.prevText,
30334 cls: "x-btn-icon x-grid-page-prev",
30336 handler: this.onClick.createDelegate(this, ["prev"])
30338 //this.addSeparator();
30339 this.add(this.beforePageText);
30340 this.field = Roo.get(this.addDom({
30345 cls: "x-grid-page-number"
30347 this.field.on("keydown", this.onPagingKeydown, this);
30348 this.field.on("focus", function(){this.dom.select();});
30349 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30350 this.field.setHeight(18);
30351 //this.addSeparator();
30352 this.next = this.addButton({
30353 tooltip: this.nextText,
30354 cls: "x-btn-icon x-grid-page-next",
30356 handler: this.onClick.createDelegate(this, ["next"])
30358 this.last = this.addButton({
30359 tooltip: this.lastText,
30360 cls: "x-btn-icon x-grid-page-last",
30362 handler: this.onClick.createDelegate(this, ["last"])
30364 //this.addSeparator();
30365 this.loading = this.addButton({
30366 tooltip: this.refreshText,
30367 cls: "x-btn-icon x-grid-loading",
30368 handler: this.onClick.createDelegate(this, ["refresh"])
30371 if(this.displayInfo){
30372 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30377 updateInfo : function(){
30378 if(this.displayEl){
30379 var count = this.ds.getCount();
30380 var msg = count == 0 ?
30384 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30386 this.displayEl.update(msg);
30391 onLoad : function(ds, r, o){
30392 this.cursor = o.params ? o.params.start : 0;
30393 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30395 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30396 this.field.dom.value = ap;
30397 this.first.setDisabled(ap == 1);
30398 this.prev.setDisabled(ap == 1);
30399 this.next.setDisabled(ap == ps);
30400 this.last.setDisabled(ap == ps);
30401 this.loading.enable();
30406 getPageData : function(){
30407 var total = this.ds.getTotalCount();
30410 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30411 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30416 onLoadError : function(){
30417 this.loading.enable();
30421 onPagingKeydown : function(e){
30422 var k = e.getKey();
30423 var d = this.getPageData();
30425 var v = this.field.dom.value, pageNum;
30426 if(!v || isNaN(pageNum = parseInt(v, 10))){
30427 this.field.dom.value = d.activePage;
30430 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30431 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30434 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))
30436 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30437 this.field.dom.value = pageNum;
30438 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30441 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30443 var v = this.field.dom.value, pageNum;
30444 var increment = (e.shiftKey) ? 10 : 1;
30445 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30448 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30449 this.field.dom.value = d.activePage;
30452 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30454 this.field.dom.value = parseInt(v, 10) + increment;
30455 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30456 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30463 beforeLoad : function(){
30465 this.loading.disable();
30470 onClick : function(which){
30474 ds.load({params:{start: 0, limit: this.pageSize}});
30477 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30480 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30483 var total = ds.getTotalCount();
30484 var extra = total % this.pageSize;
30485 var lastStart = extra ? (total - extra) : total-this.pageSize;
30486 ds.load({params:{start: lastStart, limit: this.pageSize}});
30489 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30495 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30496 * @param {Roo.data.Store} store The data store to unbind
30498 unbind : function(ds){
30499 ds.un("beforeload", this.beforeLoad, this);
30500 ds.un("load", this.onLoad, this);
30501 ds.un("loadexception", this.onLoadError, this);
30502 ds.un("remove", this.updateInfo, this);
30503 ds.un("add", this.updateInfo, this);
30504 this.ds = undefined;
30508 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30509 * @param {Roo.data.Store} store The data store to bind
30511 bind : function(ds){
30512 ds.on("beforeload", this.beforeLoad, this);
30513 ds.on("load", this.onLoad, this);
30514 ds.on("loadexception", this.onLoadError, this);
30515 ds.on("remove", this.updateInfo, this);
30516 ds.on("add", this.updateInfo, this);
30521 * Ext JS Library 1.1.1
30522 * Copyright(c) 2006-2007, Ext JS, LLC.
30524 * Originally Released Under LGPL - original licence link has changed is not relivant.
30527 * <script type="text/javascript">
30531 * @class Roo.Resizable
30532 * @extends Roo.util.Observable
30533 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30534 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30535 * 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
30536 * the element will be wrapped for you automatically.</p>
30537 * <p>Here is the list of valid resize handles:</p>
30540 ------ -------------------
30549 'hd' horizontal drag
30552 * <p>Here's an example showing the creation of a typical Resizable:</p>
30554 var resizer = new Roo.Resizable("element-id", {
30562 resizer.on("resize", myHandler);
30564 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30565 * resizer.east.setDisplayed(false);</p>
30566 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30567 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30568 * resize operation's new size (defaults to [0, 0])
30569 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30570 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30571 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30572 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30573 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30574 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30575 * @cfg {Number} width The width of the element in pixels (defaults to null)
30576 * @cfg {Number} height The height of the element in pixels (defaults to null)
30577 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30578 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30579 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30580 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30581 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30582 * in favor of the handles config option (defaults to false)
30583 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30584 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30585 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30586 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30587 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30588 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30589 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30590 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30591 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30592 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30593 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30595 * Create a new resizable component
30596 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30597 * @param {Object} config configuration options
30599 Roo.Resizable = function(el, config)
30601 this.el = Roo.get(el);
30603 if(config && config.wrap){
30604 config.resizeChild = this.el;
30605 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30606 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30607 this.el.setStyle("overflow", "hidden");
30608 this.el.setPositioning(config.resizeChild.getPositioning());
30609 config.resizeChild.clearPositioning();
30610 if(!config.width || !config.height){
30611 var csize = config.resizeChild.getSize();
30612 this.el.setSize(csize.width, csize.height);
30614 if(config.pinned && !config.adjustments){
30615 config.adjustments = "auto";
30619 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30620 this.proxy.unselectable();
30621 this.proxy.enableDisplayMode('block');
30623 Roo.apply(this, config);
30626 this.disableTrackOver = true;
30627 this.el.addClass("x-resizable-pinned");
30629 // if the element isn't positioned, make it relative
30630 var position = this.el.getStyle("position");
30631 if(position != "absolute" && position != "fixed"){
30632 this.el.setStyle("position", "relative");
30634 if(!this.handles){ // no handles passed, must be legacy style
30635 this.handles = 's,e,se';
30636 if(this.multiDirectional){
30637 this.handles += ',n,w';
30640 if(this.handles == "all"){
30641 this.handles = "n s e w ne nw se sw";
30643 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30644 var ps = Roo.Resizable.positions;
30645 for(var i = 0, len = hs.length; i < len; i++){
30646 if(hs[i] && ps[hs[i]]){
30647 var pos = ps[hs[i]];
30648 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30652 this.corner = this.southeast;
30654 // updateBox = the box can move..
30655 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30656 this.updateBox = true;
30659 this.activeHandle = null;
30661 if(this.resizeChild){
30662 if(typeof this.resizeChild == "boolean"){
30663 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30665 this.resizeChild = Roo.get(this.resizeChild, true);
30669 if(this.adjustments == "auto"){
30670 var rc = this.resizeChild;
30671 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30672 if(rc && (hw || hn)){
30673 rc.position("relative");
30674 rc.setLeft(hw ? hw.el.getWidth() : 0);
30675 rc.setTop(hn ? hn.el.getHeight() : 0);
30677 this.adjustments = [
30678 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30679 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30683 if(this.draggable){
30684 this.dd = this.dynamic ?
30685 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30686 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30692 * @event beforeresize
30693 * Fired before resize is allowed. Set enabled to false to cancel resize.
30694 * @param {Roo.Resizable} this
30695 * @param {Roo.EventObject} e The mousedown event
30697 "beforeresize" : true,
30700 * Fired a resizing.
30701 * @param {Roo.Resizable} this
30702 * @param {Number} x The new x position
30703 * @param {Number} y The new y position
30704 * @param {Number} w The new w width
30705 * @param {Number} h The new h hight
30706 * @param {Roo.EventObject} e The mouseup event
30711 * Fired after a resize.
30712 * @param {Roo.Resizable} this
30713 * @param {Number} width The new width
30714 * @param {Number} height The new height
30715 * @param {Roo.EventObject} e The mouseup event
30720 if(this.width !== null && this.height !== null){
30721 this.resizeTo(this.width, this.height);
30723 this.updateChildSize();
30726 this.el.dom.style.zoom = 1;
30728 Roo.Resizable.superclass.constructor.call(this);
30731 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30732 resizeChild : false,
30733 adjustments : [0, 0],
30743 multiDirectional : false,
30744 disableTrackOver : false,
30745 easing : 'easeOutStrong',
30746 widthIncrement : 0,
30747 heightIncrement : 0,
30751 preserveRatio : false,
30752 transparent: false,
30758 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30760 constrainTo: undefined,
30762 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30764 resizeRegion: undefined,
30768 * Perform a manual resize
30769 * @param {Number} width
30770 * @param {Number} height
30772 resizeTo : function(width, height){
30773 this.el.setSize(width, height);
30774 this.updateChildSize();
30775 this.fireEvent("resize", this, width, height, null);
30779 startSizing : function(e, handle){
30780 this.fireEvent("beforeresize", this, e);
30781 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30784 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30785 this.overlay.unselectable();
30786 this.overlay.enableDisplayMode("block");
30787 this.overlay.on("mousemove", this.onMouseMove, this);
30788 this.overlay.on("mouseup", this.onMouseUp, this);
30790 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30792 this.resizing = true;
30793 this.startBox = this.el.getBox();
30794 this.startPoint = e.getXY();
30795 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30796 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30798 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30799 this.overlay.show();
30801 if(this.constrainTo) {
30802 var ct = Roo.get(this.constrainTo);
30803 this.resizeRegion = ct.getRegion().adjust(
30804 ct.getFrameWidth('t'),
30805 ct.getFrameWidth('l'),
30806 -ct.getFrameWidth('b'),
30807 -ct.getFrameWidth('r')
30811 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30813 this.proxy.setBox(this.startBox);
30815 this.proxy.setStyle('visibility', 'visible');
30821 onMouseDown : function(handle, e){
30824 this.activeHandle = handle;
30825 this.startSizing(e, handle);
30830 onMouseUp : function(e){
30831 var size = this.resizeElement();
30832 this.resizing = false;
30834 this.overlay.hide();
30836 this.fireEvent("resize", this, size.width, size.height, e);
30840 updateChildSize : function(){
30842 if(this.resizeChild){
30844 var child = this.resizeChild;
30845 var adj = this.adjustments;
30846 if(el.dom.offsetWidth){
30847 var b = el.getSize(true);
30848 child.setSize(b.width+adj[0], b.height+adj[1]);
30850 // Second call here for IE
30851 // The first call enables instant resizing and
30852 // the second call corrects scroll bars if they
30855 setTimeout(function(){
30856 if(el.dom.offsetWidth){
30857 var b = el.getSize(true);
30858 child.setSize(b.width+adj[0], b.height+adj[1]);
30866 snap : function(value, inc, min){
30867 if(!inc || !value) {
30870 var newValue = value;
30871 var m = value % inc;
30874 newValue = value + (inc-m);
30876 newValue = value - m;
30879 return Math.max(min, newValue);
30883 resizeElement : function(){
30884 var box = this.proxy.getBox();
30885 if(this.updateBox){
30886 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
30888 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
30890 this.updateChildSize();
30898 constrain : function(v, diff, m, mx){
30901 }else if(v - diff > mx){
30908 onMouseMove : function(e){
30911 try{// try catch so if something goes wrong the user doesn't get hung
30913 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
30917 //var curXY = this.startPoint;
30918 var curSize = this.curSize || this.startBox;
30919 var x = this.startBox.x, y = this.startBox.y;
30920 var ox = x, oy = y;
30921 var w = curSize.width, h = curSize.height;
30922 var ow = w, oh = h;
30923 var mw = this.minWidth, mh = this.minHeight;
30924 var mxw = this.maxWidth, mxh = this.maxHeight;
30925 var wi = this.widthIncrement;
30926 var hi = this.heightIncrement;
30928 var eventXY = e.getXY();
30929 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
30930 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
30932 var pos = this.activeHandle.position;
30937 w = Math.min(Math.max(mw, w), mxw);
30942 h = Math.min(Math.max(mh, h), mxh);
30947 w = Math.min(Math.max(mw, w), mxw);
30948 h = Math.min(Math.max(mh, h), mxh);
30951 diffY = this.constrain(h, diffY, mh, mxh);
30958 var adiffX = Math.abs(diffX);
30959 var sub = (adiffX % wi); // how much
30960 if (sub > (wi/2)) { // far enough to snap
30961 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
30963 // remove difference..
30964 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
30968 x = Math.max(this.minX, x);
30971 diffX = this.constrain(w, diffX, mw, mxw);
30977 w = Math.min(Math.max(mw, w), mxw);
30978 diffY = this.constrain(h, diffY, mh, mxh);
30983 diffX = this.constrain(w, diffX, mw, mxw);
30984 diffY = this.constrain(h, diffY, mh, mxh);
30991 diffX = this.constrain(w, diffX, mw, mxw);
30993 h = Math.min(Math.max(mh, h), mxh);
30999 var sw = this.snap(w, wi, mw);
31000 var sh = this.snap(h, hi, mh);
31001 if(sw != w || sh != h){
31024 if(this.preserveRatio){
31029 h = Math.min(Math.max(mh, h), mxh);
31034 w = Math.min(Math.max(mw, w), mxw);
31039 w = Math.min(Math.max(mw, w), mxw);
31045 w = Math.min(Math.max(mw, w), mxw);
31051 h = Math.min(Math.max(mh, h), mxh);
31059 h = Math.min(Math.max(mh, h), mxh);
31069 h = Math.min(Math.max(mh, h), mxh);
31077 if (pos == 'hdrag') {
31080 this.proxy.setBounds(x, y, w, h);
31082 this.resizeElement();
31086 this.fireEvent("resizing", this, x, y, w, h, e);
31090 handleOver : function(){
31092 this.el.addClass("x-resizable-over");
31097 handleOut : function(){
31098 if(!this.resizing){
31099 this.el.removeClass("x-resizable-over");
31104 * Returns the element this component is bound to.
31105 * @return {Roo.Element}
31107 getEl : function(){
31112 * Returns the resizeChild element (or null).
31113 * @return {Roo.Element}
31115 getResizeChild : function(){
31116 return this.resizeChild;
31118 groupHandler : function()
31123 * Destroys this resizable. If the element was wrapped and
31124 * removeEl is not true then the element remains.
31125 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31127 destroy : function(removeEl){
31128 this.proxy.remove();
31130 this.overlay.removeAllListeners();
31131 this.overlay.remove();
31133 var ps = Roo.Resizable.positions;
31135 if(typeof ps[k] != "function" && this[ps[k]]){
31136 var h = this[ps[k]];
31137 h.el.removeAllListeners();
31142 this.el.update("");
31149 // hash to map config positions to true positions
31150 Roo.Resizable.positions = {
31151 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31156 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31158 // only initialize the template if resizable is used
31159 var tpl = Roo.DomHelper.createTemplate(
31160 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31163 Roo.Resizable.Handle.prototype.tpl = tpl;
31165 this.position = pos;
31167 // show north drag fro topdra
31168 var handlepos = pos == 'hdrag' ? 'north' : pos;
31170 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31171 if (pos == 'hdrag') {
31172 this.el.setStyle('cursor', 'pointer');
31174 this.el.unselectable();
31176 this.el.setOpacity(0);
31178 this.el.on("mousedown", this.onMouseDown, this);
31179 if(!disableTrackOver){
31180 this.el.on("mouseover", this.onMouseOver, this);
31181 this.el.on("mouseout", this.onMouseOut, this);
31186 Roo.Resizable.Handle.prototype = {
31187 afterResize : function(rz){
31192 onMouseDown : function(e){
31193 this.rz.onMouseDown(this, e);
31196 onMouseOver : function(e){
31197 this.rz.handleOver(this, e);
31200 onMouseOut : function(e){
31201 this.rz.handleOut(this, e);
31205 * Ext JS Library 1.1.1
31206 * Copyright(c) 2006-2007, Ext JS, LLC.
31208 * Originally Released Under LGPL - original licence link has changed is not relivant.
31211 * <script type="text/javascript">
31215 * @class Roo.Editor
31216 * @extends Roo.Component
31217 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31219 * Create a new Editor
31220 * @param {Roo.form.Field} field The Field object (or descendant)
31221 * @param {Object} config The config object
31223 Roo.Editor = function(field, config){
31224 Roo.Editor.superclass.constructor.call(this, config);
31225 this.field = field;
31228 * @event beforestartedit
31229 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31230 * false from the handler of this event.
31231 * @param {Editor} this
31232 * @param {Roo.Element} boundEl The underlying element bound to this editor
31233 * @param {Mixed} value The field value being set
31235 "beforestartedit" : true,
31238 * Fires when this editor is displayed
31239 * @param {Roo.Element} boundEl The underlying element bound to this editor
31240 * @param {Mixed} value The starting field value
31242 "startedit" : true,
31244 * @event beforecomplete
31245 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31246 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31247 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31248 * event will not fire since no edit actually occurred.
31249 * @param {Editor} this
31250 * @param {Mixed} value The current field value
31251 * @param {Mixed} startValue The original field value
31253 "beforecomplete" : true,
31256 * Fires after editing is complete and any changed value has been written to the underlying field.
31257 * @param {Editor} this
31258 * @param {Mixed} value The current field value
31259 * @param {Mixed} startValue The original field value
31263 * @event specialkey
31264 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31265 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31266 * @param {Roo.form.Field} this
31267 * @param {Roo.EventObject} e The event object
31269 "specialkey" : true
31273 Roo.extend(Roo.Editor, Roo.Component, {
31275 * @cfg {Boolean/String} autosize
31276 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31277 * or "height" to adopt the height only (defaults to false)
31280 * @cfg {Boolean} revertInvalid
31281 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31282 * validation fails (defaults to true)
31285 * @cfg {Boolean} ignoreNoChange
31286 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31287 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31288 * will never be ignored.
31291 * @cfg {Boolean} hideEl
31292 * False to keep the bound element visible while the editor is displayed (defaults to true)
31295 * @cfg {Mixed} value
31296 * The data value of the underlying field (defaults to "")
31300 * @cfg {String} alignment
31301 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31305 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31306 * for bottom-right shadow (defaults to "frame")
31310 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31314 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31316 completeOnEnter : false,
31318 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31320 cancelOnEsc : false,
31322 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31327 onRender : function(ct, position){
31328 this.el = new Roo.Layer({
31329 shadow: this.shadow,
31335 constrain: this.constrain
31337 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31338 if(this.field.msgTarget != 'title'){
31339 this.field.msgTarget = 'qtip';
31341 this.field.render(this.el);
31343 this.field.el.dom.setAttribute('autocomplete', 'off');
31345 this.field.on("specialkey", this.onSpecialKey, this);
31346 if(this.swallowKeys){
31347 this.field.el.swallowEvent(['keydown','keypress']);
31350 this.field.on("blur", this.onBlur, this);
31351 if(this.field.grow){
31352 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31356 onSpecialKey : function(field, e)
31358 //Roo.log('editor onSpecialKey');
31359 if(this.completeOnEnter && e.getKey() == e.ENTER){
31361 this.completeEdit();
31364 // do not fire special key otherwise it might hide close the editor...
31365 if(e.getKey() == e.ENTER){
31368 if(this.cancelOnEsc && e.getKey() == e.ESC){
31372 this.fireEvent('specialkey', field, e);
31377 * Starts the editing process and shows the editor.
31378 * @param {String/HTMLElement/Element} el The element to edit
31379 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31380 * to the innerHTML of el.
31382 startEdit : function(el, value){
31384 this.completeEdit();
31386 this.boundEl = Roo.get(el);
31387 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31388 if(!this.rendered){
31389 this.render(this.parentEl || document.body);
31391 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31394 this.startValue = v;
31395 this.field.setValue(v);
31397 var sz = this.boundEl.getSize();
31398 switch(this.autoSize){
31400 this.setSize(sz.width, "");
31403 this.setSize("", sz.height);
31406 this.setSize(sz.width, sz.height);
31409 this.el.alignTo(this.boundEl, this.alignment);
31410 this.editing = true;
31412 Roo.QuickTips.disable();
31418 * Sets the height and width of this editor.
31419 * @param {Number} width The new width
31420 * @param {Number} height The new height
31422 setSize : function(w, h){
31423 this.field.setSize(w, h);
31430 * Realigns the editor to the bound field based on the current alignment config value.
31432 realign : function(){
31433 this.el.alignTo(this.boundEl, this.alignment);
31437 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31438 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31440 completeEdit : function(remainVisible){
31444 var v = this.getValue();
31445 if(this.revertInvalid !== false && !this.field.isValid()){
31446 v = this.startValue;
31447 this.cancelEdit(true);
31449 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31450 this.editing = false;
31454 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31455 this.editing = false;
31456 if(this.updateEl && this.boundEl){
31457 this.boundEl.update(v);
31459 if(remainVisible !== true){
31462 this.fireEvent("complete", this, v, this.startValue);
31467 onShow : function(){
31469 if(this.hideEl !== false){
31470 this.boundEl.hide();
31473 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31474 this.fixIEFocus = true;
31475 this.deferredFocus.defer(50, this);
31477 this.field.focus();
31479 this.fireEvent("startedit", this.boundEl, this.startValue);
31482 deferredFocus : function(){
31484 this.field.focus();
31489 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31490 * reverted to the original starting value.
31491 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31492 * cancel (defaults to false)
31494 cancelEdit : function(remainVisible){
31496 this.setValue(this.startValue);
31497 if(remainVisible !== true){
31504 onBlur : function(){
31505 if(this.allowBlur !== true && this.editing){
31506 this.completeEdit();
31511 onHide : function(){
31513 this.completeEdit();
31517 if(this.field.collapse){
31518 this.field.collapse();
31521 if(this.hideEl !== false){
31522 this.boundEl.show();
31525 Roo.QuickTips.enable();
31530 * Sets the data value of the editor
31531 * @param {Mixed} value Any valid value supported by the underlying field
31533 setValue : function(v){
31534 this.field.setValue(v);
31538 * Gets the data value of the editor
31539 * @return {Mixed} The data value
31541 getValue : function(){
31542 return this.field.getValue();
31546 * Ext JS Library 1.1.1
31547 * Copyright(c) 2006-2007, Ext JS, LLC.
31549 * Originally Released Under LGPL - original licence link has changed is not relivant.
31552 * <script type="text/javascript">
31556 * @class Roo.BasicDialog
31557 * @extends Roo.util.Observable
31558 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31560 var dlg = new Roo.BasicDialog("my-dlg", {
31569 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31570 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31571 dlg.addButton('Cancel', dlg.hide, dlg);
31574 <b>A Dialog should always be a direct child of the body element.</b>
31575 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31576 * @cfg {String} title Default text to display in the title bar (defaults to null)
31577 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31578 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31579 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31580 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31581 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31582 * (defaults to null with no animation)
31583 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31584 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31585 * property for valid values (defaults to 'all')
31586 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31587 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31588 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31589 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31590 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31591 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31592 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31593 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31594 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31595 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31596 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31597 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31598 * draggable = true (defaults to false)
31599 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31600 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31601 * shadow (defaults to false)
31602 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31603 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31604 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31605 * @cfg {Array} buttons Array of buttons
31606 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31608 * Create a new BasicDialog.
31609 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31610 * @param {Object} config Configuration options
31612 Roo.BasicDialog = function(el, config){
31613 this.el = Roo.get(el);
31614 var dh = Roo.DomHelper;
31615 if(!this.el && config && config.autoCreate){
31616 if(typeof config.autoCreate == "object"){
31617 if(!config.autoCreate.id){
31618 config.autoCreate.id = el;
31620 this.el = dh.append(document.body,
31621 config.autoCreate, true);
31623 this.el = dh.append(document.body,
31624 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31628 el.setDisplayed(true);
31629 el.hide = this.hideAction;
31631 el.addClass("x-dlg");
31633 Roo.apply(this, config);
31635 this.proxy = el.createProxy("x-dlg-proxy");
31636 this.proxy.hide = this.hideAction;
31637 this.proxy.setOpacity(.5);
31641 el.setWidth(config.width);
31644 el.setHeight(config.height);
31646 this.size = el.getSize();
31647 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31648 this.xy = [config.x,config.y];
31650 this.xy = el.getCenterXY(true);
31652 /** The header element @type Roo.Element */
31653 this.header = el.child("> .x-dlg-hd");
31654 /** The body element @type Roo.Element */
31655 this.body = el.child("> .x-dlg-bd");
31656 /** The footer element @type Roo.Element */
31657 this.footer = el.child("> .x-dlg-ft");
31660 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31663 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31666 this.header.unselectable();
31668 this.header.update(this.title);
31670 // this element allows the dialog to be focused for keyboard event
31671 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31672 this.focusEl.swallowEvent("click", true);
31674 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31676 // wrap the body and footer for special rendering
31677 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31679 this.bwrap.dom.appendChild(this.footer.dom);
31682 this.bg = this.el.createChild({
31683 tag: "div", cls:"x-dlg-bg",
31684 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31686 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31689 if(this.autoScroll !== false && !this.autoTabs){
31690 this.body.setStyle("overflow", "auto");
31693 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31695 if(this.closable !== false){
31696 this.el.addClass("x-dlg-closable");
31697 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31698 this.close.on("click", this.closeClick, this);
31699 this.close.addClassOnOver("x-dlg-close-over");
31701 if(this.collapsible !== false){
31702 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31703 this.collapseBtn.on("click", this.collapseClick, this);
31704 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31705 this.header.on("dblclick", this.collapseClick, this);
31707 if(this.resizable !== false){
31708 this.el.addClass("x-dlg-resizable");
31709 this.resizer = new Roo.Resizable(el, {
31710 minWidth: this.minWidth || 80,
31711 minHeight:this.minHeight || 80,
31712 handles: this.resizeHandles || "all",
31715 this.resizer.on("beforeresize", this.beforeResize, this);
31716 this.resizer.on("resize", this.onResize, this);
31718 if(this.draggable !== false){
31719 el.addClass("x-dlg-draggable");
31720 if (!this.proxyDrag) {
31721 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31724 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31726 dd.setHandleElId(this.header.id);
31727 dd.endDrag = this.endMove.createDelegate(this);
31728 dd.startDrag = this.startMove.createDelegate(this);
31729 dd.onDrag = this.onDrag.createDelegate(this);
31734 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31735 this.mask.enableDisplayMode("block");
31737 this.el.addClass("x-dlg-modal");
31740 this.shadow = new Roo.Shadow({
31741 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31742 offset : this.shadowOffset
31745 this.shadowOffset = 0;
31747 if(Roo.useShims && this.shim !== false){
31748 this.shim = this.el.createShim();
31749 this.shim.hide = this.hideAction;
31757 if (this.buttons) {
31758 var bts= this.buttons;
31760 Roo.each(bts, function(b) {
31769 * Fires when a key is pressed
31770 * @param {Roo.BasicDialog} this
31771 * @param {Roo.EventObject} e
31776 * Fires when this dialog is moved by the user.
31777 * @param {Roo.BasicDialog} this
31778 * @param {Number} x The new page X
31779 * @param {Number} y The new page Y
31784 * Fires when this dialog is resized by the user.
31785 * @param {Roo.BasicDialog} this
31786 * @param {Number} width The new width
31787 * @param {Number} height The new height
31791 * @event beforehide
31792 * Fires before this dialog is hidden.
31793 * @param {Roo.BasicDialog} this
31795 "beforehide" : true,
31798 * Fires when this dialog is hidden.
31799 * @param {Roo.BasicDialog} this
31803 * @event beforeshow
31804 * Fires before this dialog is shown.
31805 * @param {Roo.BasicDialog} this
31807 "beforeshow" : true,
31810 * Fires when this dialog is shown.
31811 * @param {Roo.BasicDialog} this
31815 el.on("keydown", this.onKeyDown, this);
31816 el.on("mousedown", this.toFront, this);
31817 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31819 Roo.DialogManager.register(this);
31820 Roo.BasicDialog.superclass.constructor.call(this);
31823 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31824 shadowOffset: Roo.isIE ? 6 : 5,
31827 minButtonWidth: 75,
31828 defaultButton: null,
31829 buttonAlign: "right",
31834 * Sets the dialog title text
31835 * @param {String} text The title text to display
31836 * @return {Roo.BasicDialog} this
31838 setTitle : function(text){
31839 this.header.update(text);
31844 closeClick : function(){
31849 collapseClick : function(){
31850 this[this.collapsed ? "expand" : "collapse"]();
31854 * Collapses the dialog to its minimized state (only the title bar is visible).
31855 * Equivalent to the user clicking the collapse dialog button.
31857 collapse : function(){
31858 if(!this.collapsed){
31859 this.collapsed = true;
31860 this.el.addClass("x-dlg-collapsed");
31861 this.restoreHeight = this.el.getHeight();
31862 this.resizeTo(this.el.getWidth(), this.header.getHeight());
31867 * Expands a collapsed dialog back to its normal state. Equivalent to the user
31868 * clicking the expand dialog button.
31870 expand : function(){
31871 if(this.collapsed){
31872 this.collapsed = false;
31873 this.el.removeClass("x-dlg-collapsed");
31874 this.resizeTo(this.el.getWidth(), this.restoreHeight);
31879 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
31880 * @return {Roo.TabPanel} The tabs component
31882 initTabs : function(){
31883 var tabs = this.getTabs();
31884 while(tabs.getTab(0)){
31887 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
31889 tabs.addTab(Roo.id(dom), dom.title);
31897 beforeResize : function(){
31898 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
31902 onResize : function(){
31903 this.refreshSize();
31904 this.syncBodyHeight();
31905 this.adjustAssets();
31907 this.fireEvent("resize", this, this.size.width, this.size.height);
31911 onKeyDown : function(e){
31912 if(this.isVisible()){
31913 this.fireEvent("keydown", this, e);
31918 * Resizes the dialog.
31919 * @param {Number} width
31920 * @param {Number} height
31921 * @return {Roo.BasicDialog} this
31923 resizeTo : function(width, height){
31924 this.el.setSize(width, height);
31925 this.size = {width: width, height: height};
31926 this.syncBodyHeight();
31927 if(this.fixedcenter){
31930 if(this.isVisible()){
31931 this.constrainXY();
31932 this.adjustAssets();
31934 this.fireEvent("resize", this, width, height);
31940 * Resizes the dialog to fit the specified content size.
31941 * @param {Number} width
31942 * @param {Number} height
31943 * @return {Roo.BasicDialog} this
31945 setContentSize : function(w, h){
31946 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
31947 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
31948 //if(!this.el.isBorderBox()){
31949 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
31950 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
31953 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
31954 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
31956 this.resizeTo(w, h);
31961 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
31962 * executed in response to a particular key being pressed while the dialog is active.
31963 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
31964 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
31965 * @param {Function} fn The function to call
31966 * @param {Object} scope (optional) The scope of the function
31967 * @return {Roo.BasicDialog} this
31969 addKeyListener : function(key, fn, scope){
31970 var keyCode, shift, ctrl, alt;
31971 if(typeof key == "object" && !(key instanceof Array)){
31972 keyCode = key["key"];
31973 shift = key["shift"];
31974 ctrl = key["ctrl"];
31979 var handler = function(dlg, e){
31980 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
31981 var k = e.getKey();
31982 if(keyCode instanceof Array){
31983 for(var i = 0, len = keyCode.length; i < len; i++){
31984 if(keyCode[i] == k){
31985 fn.call(scope || window, dlg, k, e);
31991 fn.call(scope || window, dlg, k, e);
31996 this.on("keydown", handler);
32001 * Returns the TabPanel component (creates it if it doesn't exist).
32002 * Note: If you wish to simply check for the existence of tabs without creating them,
32003 * check for a null 'tabs' property.
32004 * @return {Roo.TabPanel} The tabs component
32006 getTabs : function(){
32008 this.el.addClass("x-dlg-auto-tabs");
32009 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32010 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32016 * Adds a button to the footer section of the dialog.
32017 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32018 * object or a valid Roo.DomHelper element config
32019 * @param {Function} handler The function called when the button is clicked
32020 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32021 * @return {Roo.Button} The new button
32023 addButton : function(config, handler, scope){
32024 var dh = Roo.DomHelper;
32026 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32028 if(!this.btnContainer){
32029 var tb = this.footer.createChild({
32031 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32032 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32034 this.btnContainer = tb.firstChild.firstChild.firstChild;
32039 minWidth: this.minButtonWidth,
32042 if(typeof config == "string"){
32043 bconfig.text = config;
32046 bconfig.dhconfig = config;
32048 Roo.apply(bconfig, config);
32052 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32053 bconfig.position = Math.max(0, bconfig.position);
32054 fc = this.btnContainer.childNodes[bconfig.position];
32057 var btn = new Roo.Button(
32059 this.btnContainer.insertBefore(document.createElement("td"),fc)
32060 : this.btnContainer.appendChild(document.createElement("td")),
32061 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32064 this.syncBodyHeight();
32067 * Array of all the buttons that have been added to this dialog via addButton
32072 this.buttons.push(btn);
32077 * Sets the default button to be focused when the dialog is displayed.
32078 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32079 * @return {Roo.BasicDialog} this
32081 setDefaultButton : function(btn){
32082 this.defaultButton = btn;
32087 getHeaderFooterHeight : function(safe){
32090 height += this.header.getHeight();
32093 var fm = this.footer.getMargins();
32094 height += (this.footer.getHeight()+fm.top+fm.bottom);
32096 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32097 height += this.centerBg.getPadding("tb");
32102 syncBodyHeight : function()
32104 var bd = this.body, // the text
32105 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32107 var height = this.size.height - this.getHeaderFooterHeight(false);
32108 bd.setHeight(height-bd.getMargins("tb"));
32109 var hh = this.header.getHeight();
32110 var h = this.size.height-hh;
32113 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32114 bw.setHeight(h-cb.getPadding("tb"));
32116 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32117 bd.setWidth(bw.getWidth(true));
32119 this.tabs.syncHeight();
32121 this.tabs.el.repaint();
32127 * Restores the previous state of the dialog if Roo.state is configured.
32128 * @return {Roo.BasicDialog} this
32130 restoreState : function(){
32131 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32132 if(box && box.width){
32133 this.xy = [box.x, box.y];
32134 this.resizeTo(box.width, box.height);
32140 beforeShow : function(){
32142 if(this.fixedcenter){
32143 this.xy = this.el.getCenterXY(true);
32146 Roo.get(document.body).addClass("x-body-masked");
32147 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32150 this.constrainXY();
32154 animShow : function(){
32155 var b = Roo.get(this.animateTarget).getBox();
32156 this.proxy.setSize(b.width, b.height);
32157 this.proxy.setLocation(b.x, b.y);
32159 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32160 true, .35, this.showEl.createDelegate(this));
32164 * Shows the dialog.
32165 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32166 * @return {Roo.BasicDialog} this
32168 show : function(animateTarget){
32169 if (this.fireEvent("beforeshow", this) === false){
32172 if(this.syncHeightBeforeShow){
32173 this.syncBodyHeight();
32174 }else if(this.firstShow){
32175 this.firstShow = false;
32176 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32178 this.animateTarget = animateTarget || this.animateTarget;
32179 if(!this.el.isVisible()){
32181 if(this.animateTarget && Roo.get(this.animateTarget)){
32191 showEl : function(){
32193 this.el.setXY(this.xy);
32195 this.adjustAssets(true);
32198 // IE peekaboo bug - fix found by Dave Fenwick
32202 this.fireEvent("show", this);
32206 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32207 * dialog itself will receive focus.
32209 focus : function(){
32210 if(this.defaultButton){
32211 this.defaultButton.focus();
32213 this.focusEl.focus();
32218 constrainXY : function(){
32219 if(this.constraintoviewport !== false){
32220 if(!this.viewSize){
32221 if(this.container){
32222 var s = this.container.getSize();
32223 this.viewSize = [s.width, s.height];
32225 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32228 var s = Roo.get(this.container||document).getScroll();
32230 var x = this.xy[0], y = this.xy[1];
32231 var w = this.size.width, h = this.size.height;
32232 var vw = this.viewSize[0], vh = this.viewSize[1];
32233 // only move it if it needs it
32235 // first validate right/bottom
32236 if(x + w > vw+s.left){
32240 if(y + h > vh+s.top){
32244 // then make sure top/left isn't negative
32256 if(this.isVisible()){
32257 this.el.setLocation(x, y);
32258 this.adjustAssets();
32265 onDrag : function(){
32266 if(!this.proxyDrag){
32267 this.xy = this.el.getXY();
32268 this.adjustAssets();
32273 adjustAssets : function(doShow){
32274 var x = this.xy[0], y = this.xy[1];
32275 var w = this.size.width, h = this.size.height;
32276 if(doShow === true){
32278 this.shadow.show(this.el);
32284 if(this.shadow && this.shadow.isVisible()){
32285 this.shadow.show(this.el);
32287 if(this.shim && this.shim.isVisible()){
32288 this.shim.setBounds(x, y, w, h);
32293 adjustViewport : function(w, h){
32295 w = Roo.lib.Dom.getViewWidth();
32296 h = Roo.lib.Dom.getViewHeight();
32299 this.viewSize = [w, h];
32300 if(this.modal && this.mask.isVisible()){
32301 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32302 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32304 if(this.isVisible()){
32305 this.constrainXY();
32310 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32311 * shadow, proxy, mask, etc.) Also removes all event listeners.
32312 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32314 destroy : function(removeEl){
32315 if(this.isVisible()){
32316 this.animateTarget = null;
32319 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32321 this.tabs.destroy(removeEl);
32334 for(var i = 0, len = this.buttons.length; i < len; i++){
32335 this.buttons[i].destroy();
32338 this.el.removeAllListeners();
32339 if(removeEl === true){
32340 this.el.update("");
32343 Roo.DialogManager.unregister(this);
32347 startMove : function(){
32348 if(this.proxyDrag){
32351 if(this.constraintoviewport !== false){
32352 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32357 endMove : function(){
32358 if(!this.proxyDrag){
32359 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32361 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32364 this.refreshSize();
32365 this.adjustAssets();
32367 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32371 * Brings this dialog to the front of any other visible dialogs
32372 * @return {Roo.BasicDialog} this
32374 toFront : function(){
32375 Roo.DialogManager.bringToFront(this);
32380 * Sends this dialog to the back (under) of any other visible dialogs
32381 * @return {Roo.BasicDialog} this
32383 toBack : function(){
32384 Roo.DialogManager.sendToBack(this);
32389 * Centers this dialog in the viewport
32390 * @return {Roo.BasicDialog} this
32392 center : function(){
32393 var xy = this.el.getCenterXY(true);
32394 this.moveTo(xy[0], xy[1]);
32399 * Moves the dialog's top-left corner to the specified point
32400 * @param {Number} x
32401 * @param {Number} y
32402 * @return {Roo.BasicDialog} this
32404 moveTo : function(x, y){
32406 if(this.isVisible()){
32407 this.el.setXY(this.xy);
32408 this.adjustAssets();
32414 * Aligns the dialog to the specified element
32415 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32416 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32417 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32418 * @return {Roo.BasicDialog} this
32420 alignTo : function(element, position, offsets){
32421 this.xy = this.el.getAlignToXY(element, position, offsets);
32422 if(this.isVisible()){
32423 this.el.setXY(this.xy);
32424 this.adjustAssets();
32430 * Anchors an element to another element and realigns it when the window is resized.
32431 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32432 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32433 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32434 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32435 * is a number, it is used as the buffer delay (defaults to 50ms).
32436 * @return {Roo.BasicDialog} this
32438 anchorTo : function(el, alignment, offsets, monitorScroll){
32439 var action = function(){
32440 this.alignTo(el, alignment, offsets);
32442 Roo.EventManager.onWindowResize(action, this);
32443 var tm = typeof monitorScroll;
32444 if(tm != 'undefined'){
32445 Roo.EventManager.on(window, 'scroll', action, this,
32446 {buffer: tm == 'number' ? monitorScroll : 50});
32453 * Returns true if the dialog is visible
32454 * @return {Boolean}
32456 isVisible : function(){
32457 return this.el.isVisible();
32461 animHide : function(callback){
32462 var b = Roo.get(this.animateTarget).getBox();
32464 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32466 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32467 this.hideEl.createDelegate(this, [callback]));
32471 * Hides the dialog.
32472 * @param {Function} callback (optional) Function to call when the dialog is hidden
32473 * @return {Roo.BasicDialog} this
32475 hide : function(callback){
32476 if (this.fireEvent("beforehide", this) === false){
32480 this.shadow.hide();
32485 // sometimes animateTarget seems to get set.. causing problems...
32486 // this just double checks..
32487 if(this.animateTarget && Roo.get(this.animateTarget)) {
32488 this.animHide(callback);
32491 this.hideEl(callback);
32497 hideEl : function(callback){
32501 Roo.get(document.body).removeClass("x-body-masked");
32503 this.fireEvent("hide", this);
32504 if(typeof callback == "function"){
32510 hideAction : function(){
32511 this.setLeft("-10000px");
32512 this.setTop("-10000px");
32513 this.setStyle("visibility", "hidden");
32517 refreshSize : function(){
32518 this.size = this.el.getSize();
32519 this.xy = this.el.getXY();
32520 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32524 // z-index is managed by the DialogManager and may be overwritten at any time
32525 setZIndex : function(index){
32527 this.mask.setStyle("z-index", index);
32530 this.shim.setStyle("z-index", ++index);
32533 this.shadow.setZIndex(++index);
32535 this.el.setStyle("z-index", ++index);
32537 this.proxy.setStyle("z-index", ++index);
32540 this.resizer.proxy.setStyle("z-index", ++index);
32543 this.lastZIndex = index;
32547 * Returns the element for this dialog
32548 * @return {Roo.Element} The underlying dialog Element
32550 getEl : function(){
32556 * @class Roo.DialogManager
32557 * Provides global access to BasicDialogs that have been created and
32558 * support for z-indexing (layering) multiple open dialogs.
32560 Roo.DialogManager = function(){
32562 var accessList = [];
32566 var sortDialogs = function(d1, d2){
32567 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32571 var orderDialogs = function(){
32572 accessList.sort(sortDialogs);
32573 var seed = Roo.DialogManager.zseed;
32574 for(var i = 0, len = accessList.length; i < len; i++){
32575 var dlg = accessList[i];
32577 dlg.setZIndex(seed + (i*10));
32584 * The starting z-index for BasicDialogs (defaults to 9000)
32585 * @type Number The z-index value
32590 register : function(dlg){
32591 list[dlg.id] = dlg;
32592 accessList.push(dlg);
32596 unregister : function(dlg){
32597 delete list[dlg.id];
32600 if(!accessList.indexOf){
32601 for( i = 0, len = accessList.length; i < len; i++){
32602 if(accessList[i] == dlg){
32603 accessList.splice(i, 1);
32608 i = accessList.indexOf(dlg);
32610 accessList.splice(i, 1);
32616 * Gets a registered dialog by id
32617 * @param {String/Object} id The id of the dialog or a dialog
32618 * @return {Roo.BasicDialog} this
32620 get : function(id){
32621 return typeof id == "object" ? id : list[id];
32625 * Brings the specified dialog to the front
32626 * @param {String/Object} dlg The id of the dialog or a dialog
32627 * @return {Roo.BasicDialog} this
32629 bringToFront : function(dlg){
32630 dlg = this.get(dlg);
32633 dlg._lastAccess = new Date().getTime();
32640 * Sends the specified dialog to the back
32641 * @param {String/Object} dlg The id of the dialog or a dialog
32642 * @return {Roo.BasicDialog} this
32644 sendToBack : function(dlg){
32645 dlg = this.get(dlg);
32646 dlg._lastAccess = -(new Date().getTime());
32652 * Hides all dialogs
32654 hideAll : function(){
32655 for(var id in list){
32656 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32665 * @class Roo.LayoutDialog
32666 * @extends Roo.BasicDialog
32667 * Dialog which provides adjustments for working with a layout in a Dialog.
32668 * Add your necessary layout config options to the dialog's config.<br>
32669 * Example usage (including a nested layout):
32672 dialog = new Roo.LayoutDialog("download-dlg", {
32681 // layout config merges with the dialog config
32683 tabPosition: "top",
32684 alwaysShowTabs: true
32687 dialog.addKeyListener(27, dialog.hide, dialog);
32688 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32689 dialog.addButton("Build It!", this.getDownload, this);
32691 // we can even add nested layouts
32692 var innerLayout = new Roo.BorderLayout("dl-inner", {
32702 innerLayout.beginUpdate();
32703 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32704 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32705 innerLayout.endUpdate(true);
32707 var layout = dialog.getLayout();
32708 layout.beginUpdate();
32709 layout.add("center", new Roo.ContentPanel("standard-panel",
32710 {title: "Download the Source", fitToFrame:true}));
32711 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32712 {title: "Build your own roo.js"}));
32713 layout.getRegion("center").showPanel(sp);
32714 layout.endUpdate();
32718 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32719 * @param {Object} config configuration options
32721 Roo.LayoutDialog = function(el, cfg){
32724 if (typeof(cfg) == 'undefined') {
32725 config = Roo.apply({}, el);
32726 // not sure why we use documentElement here.. - it should always be body.
32727 // IE7 borks horribly if we use documentElement.
32728 // webkit also does not like documentElement - it creates a body element...
32729 el = Roo.get( document.body || document.documentElement ).createChild();
32730 //config.autoCreate = true;
32734 config.autoTabs = false;
32735 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32736 this.body.setStyle({overflow:"hidden", position:"relative"});
32737 this.layout = new Roo.BorderLayout(this.body.dom, config);
32738 this.layout.monitorWindowResize = false;
32739 this.el.addClass("x-dlg-auto-layout");
32740 // fix case when center region overwrites center function
32741 this.center = Roo.BasicDialog.prototype.center;
32742 this.on("show", this.layout.layout, this.layout, true);
32743 if (config.items) {
32744 var xitems = config.items;
32745 delete config.items;
32746 Roo.each(xitems, this.addxtype, this);
32751 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32753 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32756 endUpdate : function(){
32757 this.layout.endUpdate();
32761 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32764 beginUpdate : function(){
32765 this.layout.beginUpdate();
32769 * Get the BorderLayout for this dialog
32770 * @return {Roo.BorderLayout}
32772 getLayout : function(){
32773 return this.layout;
32776 showEl : function(){
32777 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32779 this.layout.layout();
32784 // Use the syncHeightBeforeShow config option to control this automatically
32785 syncBodyHeight : function(){
32786 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32787 if(this.layout){this.layout.layout();}
32791 * Add an xtype element (actually adds to the layout.)
32792 * @return {Object} xdata xtype object data.
32795 addxtype : function(c) {
32796 return this.layout.addxtype(c);
32800 * Ext JS Library 1.1.1
32801 * Copyright(c) 2006-2007, Ext JS, LLC.
32803 * Originally Released Under LGPL - original licence link has changed is not relivant.
32806 * <script type="text/javascript">
32810 * @class Roo.MessageBox
32811 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32815 Roo.Msg.alert('Status', 'Changes saved successfully.');
32817 // Prompt for user data:
32818 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32820 // process text value...
32824 // Show a dialog using config options:
32826 title:'Save Changes?',
32827 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32828 buttons: Roo.Msg.YESNOCANCEL,
32835 Roo.MessageBox = function(){
32836 var dlg, opt, mask, waitTimer;
32837 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32838 var buttons, activeTextEl, bwidth;
32841 var handleButton = function(button){
32843 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
32847 var handleHide = function(){
32848 if(opt && opt.cls){
32849 dlg.el.removeClass(opt.cls);
32852 Roo.TaskMgr.stop(waitTimer);
32858 var updateButtons = function(b){
32861 buttons["ok"].hide();
32862 buttons["cancel"].hide();
32863 buttons["yes"].hide();
32864 buttons["no"].hide();
32865 dlg.footer.dom.style.display = 'none';
32868 dlg.footer.dom.style.display = '';
32869 for(var k in buttons){
32870 if(typeof buttons[k] != "function"){
32873 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
32874 width += buttons[k].el.getWidth()+15;
32884 var handleEsc = function(d, k, e){
32885 if(opt && opt.closable !== false){
32895 * Returns a reference to the underlying {@link Roo.BasicDialog} element
32896 * @return {Roo.BasicDialog} The BasicDialog element
32898 getDialog : function(){
32900 dlg = new Roo.BasicDialog("x-msg-box", {
32905 constraintoviewport:false,
32907 collapsible : false,
32910 width:400, height:100,
32911 buttonAlign:"center",
32912 closeClick : function(){
32913 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
32914 handleButton("no");
32916 handleButton("cancel");
32920 dlg.on("hide", handleHide);
32922 dlg.addKeyListener(27, handleEsc);
32924 var bt = this.buttonText;
32925 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
32926 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
32927 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
32928 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
32929 bodyEl = dlg.body.createChild({
32931 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>'
32933 msgEl = bodyEl.dom.firstChild;
32934 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
32935 textboxEl.enableDisplayMode();
32936 textboxEl.addKeyListener([10,13], function(){
32937 if(dlg.isVisible() && opt && opt.buttons){
32938 if(opt.buttons.ok){
32939 handleButton("ok");
32940 }else if(opt.buttons.yes){
32941 handleButton("yes");
32945 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
32946 textareaEl.enableDisplayMode();
32947 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
32948 progressEl.enableDisplayMode();
32949 var pf = progressEl.dom.firstChild;
32951 pp = Roo.get(pf.firstChild);
32952 pp.setHeight(pf.offsetHeight);
32960 * Updates the message box body text
32961 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
32962 * the XHTML-compliant non-breaking space character '&#160;')
32963 * @return {Roo.MessageBox} This message box
32965 updateText : function(text){
32966 if(!dlg.isVisible() && !opt.width){
32967 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
32969 msgEl.innerHTML = text || ' ';
32971 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
32972 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
32974 Math.min(opt.width || cw , this.maxWidth),
32975 Math.max(opt.minWidth || this.minWidth, bwidth)
32978 activeTextEl.setWidth(w);
32980 if(dlg.isVisible()){
32981 dlg.fixedcenter = false;
32983 // to big, make it scroll. = But as usual stupid IE does not support
32986 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
32987 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
32988 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
32990 bodyEl.dom.style.height = '';
32991 bodyEl.dom.style.overflowY = '';
32994 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
32996 bodyEl.dom.style.overflowX = '';
32999 dlg.setContentSize(w, bodyEl.getHeight());
33000 if(dlg.isVisible()){
33001 dlg.fixedcenter = true;
33007 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33008 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33009 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33010 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33011 * @return {Roo.MessageBox} This message box
33013 updateProgress : function(value, text){
33015 this.updateText(text);
33017 if (pp) { // weird bug on my firefox - for some reason this is not defined
33018 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33024 * Returns true if the message box is currently displayed
33025 * @return {Boolean} True if the message box is visible, else false
33027 isVisible : function(){
33028 return dlg && dlg.isVisible();
33032 * Hides the message box if it is displayed
33035 if(this.isVisible()){
33041 * Displays a new message box, or reinitializes an existing message box, based on the config options
33042 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33043 * The following config object properties are supported:
33045 Property Type Description
33046 ---------- --------------- ------------------------------------------------------------------------------------
33047 animEl String/Element An id or Element from which the message box should animate as it opens and
33048 closes (defaults to undefined)
33049 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33050 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33051 closable Boolean False to hide the top-right close button (defaults to true). Note that
33052 progress and wait dialogs will ignore this property and always hide the
33053 close button as they can only be closed programmatically.
33054 cls String A custom CSS class to apply to the message box element
33055 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33056 displayed (defaults to 75)
33057 fn Function A callback function to execute after closing the dialog. The arguments to the
33058 function will be btn (the name of the button that was clicked, if applicable,
33059 e.g. "ok"), and text (the value of the active text field, if applicable).
33060 Progress and wait dialogs will ignore this option since they do not respond to
33061 user actions and can only be closed programmatically, so any required function
33062 should be called by the same code after it closes the dialog.
33063 icon String A CSS class that provides a background image to be used as an icon for
33064 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33065 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33066 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33067 modal Boolean False to allow user interaction with the page while the message box is
33068 displayed (defaults to true)
33069 msg String A string that will replace the existing message box body text (defaults
33070 to the XHTML-compliant non-breaking space character ' ')
33071 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33072 progress Boolean True to display a progress bar (defaults to false)
33073 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33074 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33075 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33076 title String The title text
33077 value String The string value to set into the active textbox element if displayed
33078 wait Boolean True to display a progress bar (defaults to false)
33079 width Number The width of the dialog in pixels
33086 msg: 'Please enter your address:',
33088 buttons: Roo.MessageBox.OKCANCEL,
33091 animEl: 'addAddressBtn'
33094 * @param {Object} config Configuration options
33095 * @return {Roo.MessageBox} This message box
33097 show : function(options)
33100 // this causes nightmares if you show one dialog after another
33101 // especially on callbacks..
33103 if(this.isVisible()){
33106 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33107 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33108 Roo.log("New Dialog Message:" + options.msg )
33109 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33110 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33113 var d = this.getDialog();
33115 d.setTitle(opt.title || " ");
33116 d.close.setDisplayed(opt.closable !== false);
33117 activeTextEl = textboxEl;
33118 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33123 textareaEl.setHeight(typeof opt.multiline == "number" ?
33124 opt.multiline : this.defaultTextHeight);
33125 activeTextEl = textareaEl;
33134 progressEl.setDisplayed(opt.progress === true);
33135 this.updateProgress(0);
33136 activeTextEl.dom.value = opt.value || "";
33138 dlg.setDefaultButton(activeTextEl);
33140 var bs = opt.buttons;
33143 db = buttons["ok"];
33144 }else if(bs && bs.yes){
33145 db = buttons["yes"];
33147 dlg.setDefaultButton(db);
33149 bwidth = updateButtons(opt.buttons);
33150 this.updateText(opt.msg);
33152 d.el.addClass(opt.cls);
33154 d.proxyDrag = opt.proxyDrag === true;
33155 d.modal = opt.modal !== false;
33156 d.mask = opt.modal !== false ? mask : false;
33157 if(!d.isVisible()){
33158 // force it to the end of the z-index stack so it gets a cursor in FF
33159 document.body.appendChild(dlg.el.dom);
33160 d.animateTarget = null;
33161 d.show(options.animEl);
33167 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33168 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33169 * and closing the message box when the process is complete.
33170 * @param {String} title The title bar text
33171 * @param {String} msg The message box body text
33172 * @return {Roo.MessageBox} This message box
33174 progress : function(title, msg){
33181 minWidth: this.minProgressWidth,
33188 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33189 * If a callback function is passed it will be called after the user clicks the button, and the
33190 * id of the button that was clicked will be passed as the only parameter to the callback
33191 * (could also be the top-right close button).
33192 * @param {String} title The title bar text
33193 * @param {String} msg The message box body text
33194 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33195 * @param {Object} scope (optional) The scope of the callback function
33196 * @return {Roo.MessageBox} This message box
33198 alert : function(title, msg, fn, scope){
33211 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33212 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33213 * You are responsible for closing the message box when the process is complete.
33214 * @param {String} msg The message box body text
33215 * @param {String} title (optional) The title bar text
33216 * @return {Roo.MessageBox} This message box
33218 wait : function(msg, title){
33229 waitTimer = Roo.TaskMgr.start({
33231 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33239 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33240 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33241 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33242 * @param {String} title The title bar text
33243 * @param {String} msg The message box body text
33244 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33245 * @param {Object} scope (optional) The scope of the callback function
33246 * @return {Roo.MessageBox} This message box
33248 confirm : function(title, msg, fn, scope){
33252 buttons: this.YESNO,
33261 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33262 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33263 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33264 * (could also be the top-right close button) and the text that was entered will be passed as the two
33265 * parameters to the callback.
33266 * @param {String} title The title bar text
33267 * @param {String} msg The message box body text
33268 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33269 * @param {Object} scope (optional) The scope of the callback function
33270 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33271 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33272 * @return {Roo.MessageBox} This message box
33274 prompt : function(title, msg, fn, scope, multiline){
33278 buttons: this.OKCANCEL,
33283 multiline: multiline,
33290 * Button config that displays a single OK button
33295 * Button config that displays Yes and No buttons
33298 YESNO : {yes:true, no:true},
33300 * Button config that displays OK and Cancel buttons
33303 OKCANCEL : {ok:true, cancel:true},
33305 * Button config that displays Yes, No and Cancel buttons
33308 YESNOCANCEL : {yes:true, no:true, cancel:true},
33311 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33314 defaultTextHeight : 75,
33316 * The maximum width in pixels of the message box (defaults to 600)
33321 * The minimum width in pixels of the message box (defaults to 100)
33326 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33327 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33330 minProgressWidth : 250,
33332 * An object containing the default button text strings that can be overriden for localized language support.
33333 * Supported properties are: ok, cancel, yes and no.
33334 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33347 * Shorthand for {@link Roo.MessageBox}
33349 Roo.Msg = Roo.MessageBox;/*
33351 * Ext JS Library 1.1.1
33352 * Copyright(c) 2006-2007, Ext JS, LLC.
33354 * Originally Released Under LGPL - original licence link has changed is not relivant.
33357 * <script type="text/javascript">
33360 * @class Roo.QuickTips
33361 * Provides attractive and customizable tooltips for any element.
33364 Roo.QuickTips = function(){
33365 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33366 var ce, bd, xy, dd;
33367 var visible = false, disabled = true, inited = false;
33368 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33370 var onOver = function(e){
33374 var t = e.getTarget();
33375 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33378 if(ce && t == ce.el){
33379 clearTimeout(hideProc);
33382 if(t && tagEls[t.id]){
33383 tagEls[t.id].el = t;
33384 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33387 var ttp, et = Roo.fly(t);
33388 var ns = cfg.namespace;
33389 if(tm.interceptTitles && t.title){
33392 t.removeAttribute("title");
33393 e.preventDefault();
33395 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33398 showProc = show.defer(tm.showDelay, tm, [{
33401 width: et.getAttributeNS(ns, cfg.width),
33402 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33403 title: et.getAttributeNS(ns, cfg.title),
33404 cls: et.getAttributeNS(ns, cfg.cls)
33409 var onOut = function(e){
33410 clearTimeout(showProc);
33411 var t = e.getTarget();
33412 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33413 hideProc = setTimeout(hide, tm.hideDelay);
33417 var onMove = function(e){
33423 if(tm.trackMouse && ce){
33428 var onDown = function(e){
33429 clearTimeout(showProc);
33430 clearTimeout(hideProc);
33432 if(tm.hideOnClick){
33435 tm.enable.defer(100, tm);
33440 var getPad = function(){
33441 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33444 var show = function(o){
33448 clearTimeout(dismissProc);
33450 if(removeCls){ // in case manually hidden
33451 el.removeClass(removeCls);
33455 el.addClass(ce.cls);
33456 removeCls = ce.cls;
33459 tipTitle.update(ce.title);
33462 tipTitle.update('');
33465 el.dom.style.width = tm.maxWidth+'px';
33466 //tipBody.dom.style.width = '';
33467 tipBodyText.update(o.text);
33468 var p = getPad(), w = ce.width;
33470 var td = tipBodyText.dom;
33471 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33472 if(aw > tm.maxWidth){
33474 }else if(aw < tm.minWidth){
33480 //tipBody.setWidth(w);
33481 el.setWidth(parseInt(w, 10) + p);
33482 if(ce.autoHide === false){
33483 close.setDisplayed(true);
33488 close.setDisplayed(false);
33494 el.avoidY = xy[1]-18;
33499 el.setStyle("visibility", "visible");
33500 el.fadeIn({callback: afterShow});
33506 var afterShow = function(){
33510 if(tm.autoDismiss && ce.autoHide !== false){
33511 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33516 var hide = function(noanim){
33517 clearTimeout(dismissProc);
33518 clearTimeout(hideProc);
33520 if(el.isVisible()){
33522 if(noanim !== true && tm.animate){
33523 el.fadeOut({callback: afterHide});
33530 var afterHide = function(){
33533 el.removeClass(removeCls);
33540 * @cfg {Number} minWidth
33541 * The minimum width of the quick tip (defaults to 40)
33545 * @cfg {Number} maxWidth
33546 * The maximum width of the quick tip (defaults to 300)
33550 * @cfg {Boolean} interceptTitles
33551 * True to automatically use the element's DOM title value if available (defaults to false)
33553 interceptTitles : false,
33555 * @cfg {Boolean} trackMouse
33556 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33558 trackMouse : false,
33560 * @cfg {Boolean} hideOnClick
33561 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33563 hideOnClick : true,
33565 * @cfg {Number} showDelay
33566 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33570 * @cfg {Number} hideDelay
33571 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33575 * @cfg {Boolean} autoHide
33576 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33577 * Used in conjunction with hideDelay.
33582 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33583 * (defaults to true). Used in conjunction with autoDismissDelay.
33585 autoDismiss : true,
33588 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33590 autoDismissDelay : 5000,
33592 * @cfg {Boolean} animate
33593 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33598 * @cfg {String} title
33599 * Title text to display (defaults to ''). This can be any valid HTML markup.
33603 * @cfg {String} text
33604 * Body text to display (defaults to ''). This can be any valid HTML markup.
33608 * @cfg {String} cls
33609 * A CSS class to apply to the base quick tip element (defaults to '').
33613 * @cfg {Number} width
33614 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33615 * minWidth or maxWidth.
33620 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33621 * or display QuickTips in a page.
33624 tm = Roo.QuickTips;
33625 cfg = tm.tagConfig;
33627 if(!Roo.isReady){ // allow calling of init() before onReady
33628 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33631 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33632 el.fxDefaults = {stopFx: true};
33633 // maximum custom styling
33634 //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>');
33635 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>');
33636 tipTitle = el.child('h3');
33637 tipTitle.enableDisplayMode("block");
33638 tipBody = el.child('div.x-tip-bd');
33639 tipBodyText = el.child('div.x-tip-bd-inner');
33640 //bdLeft = el.child('div.x-tip-bd-left');
33641 //bdRight = el.child('div.x-tip-bd-right');
33642 close = el.child('div.x-tip-close');
33643 close.enableDisplayMode("block");
33644 close.on("click", hide);
33645 var d = Roo.get(document);
33646 d.on("mousedown", onDown);
33647 d.on("mouseover", onOver);
33648 d.on("mouseout", onOut);
33649 d.on("mousemove", onMove);
33650 esc = d.addKeyListener(27, hide);
33653 dd = el.initDD("default", null, {
33654 onDrag : function(){
33658 dd.setHandleElId(tipTitle.id);
33667 * Configures a new quick tip instance and assigns it to a target element. The following config options
33670 Property Type Description
33671 ---------- --------------------- ------------------------------------------------------------------------
33672 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33674 * @param {Object} config The config object
33676 register : function(config){
33677 var cs = config instanceof Array ? config : arguments;
33678 for(var i = 0, len = cs.length; i < len; i++) {
33680 var target = c.target;
33682 if(target instanceof Array){
33683 for(var j = 0, jlen = target.length; j < jlen; j++){
33684 tagEls[target[j]] = c;
33687 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33694 * Removes this quick tip from its element and destroys it.
33695 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33697 unregister : function(el){
33698 delete tagEls[Roo.id(el)];
33702 * Enable this quick tip.
33704 enable : function(){
33705 if(inited && disabled){
33707 if(locks.length < 1){
33714 * Disable this quick tip.
33716 disable : function(){
33718 clearTimeout(showProc);
33719 clearTimeout(hideProc);
33720 clearTimeout(dismissProc);
33728 * Returns true if the quick tip is enabled, else false.
33730 isEnabled : function(){
33736 namespace : "roo", // was ext?? this may break..
33737 alt_namespace : "ext",
33738 attribute : "qtip",
33748 // backwards compat
33749 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33751 * Ext JS Library 1.1.1
33752 * Copyright(c) 2006-2007, Ext JS, LLC.
33754 * Originally Released Under LGPL - original licence link has changed is not relivant.
33757 * <script type="text/javascript">
33762 * @class Roo.tree.TreePanel
33763 * @extends Roo.data.Tree
33765 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33766 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33767 * @cfg {Boolean} enableDD true to enable drag and drop
33768 * @cfg {Boolean} enableDrag true to enable just drag
33769 * @cfg {Boolean} enableDrop true to enable just drop
33770 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33771 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33772 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33773 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33774 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33775 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33776 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33777 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33778 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33779 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33780 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33781 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33782 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33783 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33784 * @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>
33785 * @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>
33788 * @param {String/HTMLElement/Element} el The container element
33789 * @param {Object} config
33791 Roo.tree.TreePanel = function(el, config){
33793 var loader = false;
33795 root = config.root;
33796 delete config.root;
33798 if (config.loader) {
33799 loader = config.loader;
33800 delete config.loader;
33803 Roo.apply(this, config);
33804 Roo.tree.TreePanel.superclass.constructor.call(this);
33805 this.el = Roo.get(el);
33806 this.el.addClass('x-tree');
33807 //console.log(root);
33809 this.setRootNode( Roo.factory(root, Roo.tree));
33812 this.loader = Roo.factory(loader, Roo.tree);
33815 * Read-only. The id of the container element becomes this TreePanel's id.
33817 this.id = this.el.id;
33820 * @event beforeload
33821 * Fires before a node is loaded, return false to cancel
33822 * @param {Node} node The node being loaded
33824 "beforeload" : true,
33827 * Fires when a node is loaded
33828 * @param {Node} node The node that was loaded
33832 * @event textchange
33833 * Fires when the text for a node is changed
33834 * @param {Node} node The node
33835 * @param {String} text The new text
33836 * @param {String} oldText The old text
33838 "textchange" : true,
33840 * @event beforeexpand
33841 * Fires before a node is expanded, return false to cancel.
33842 * @param {Node} node The node
33843 * @param {Boolean} deep
33844 * @param {Boolean} anim
33846 "beforeexpand" : true,
33848 * @event beforecollapse
33849 * Fires before a node is collapsed, return false to cancel.
33850 * @param {Node} node The node
33851 * @param {Boolean} deep
33852 * @param {Boolean} anim
33854 "beforecollapse" : true,
33857 * Fires when a node is expanded
33858 * @param {Node} node The node
33862 * @event disabledchange
33863 * Fires when the disabled status of a node changes
33864 * @param {Node} node The node
33865 * @param {Boolean} disabled
33867 "disabledchange" : true,
33870 * Fires when a node is collapsed
33871 * @param {Node} node The node
33875 * @event beforeclick
33876 * Fires before click processing on a node. Return false to cancel the default action.
33877 * @param {Node} node The node
33878 * @param {Roo.EventObject} e The event object
33880 "beforeclick":true,
33882 * @event checkchange
33883 * Fires when a node with a checkbox's checked property changes
33884 * @param {Node} this This node
33885 * @param {Boolean} checked
33887 "checkchange":true,
33890 * Fires when a node is clicked
33891 * @param {Node} node The node
33892 * @param {Roo.EventObject} e The event object
33897 * Fires when a node is double clicked
33898 * @param {Node} node The node
33899 * @param {Roo.EventObject} e The event object
33903 * @event contextmenu
33904 * Fires when a node is right clicked
33905 * @param {Node} node The node
33906 * @param {Roo.EventObject} e The event object
33908 "contextmenu":true,
33910 * @event beforechildrenrendered
33911 * Fires right before the child nodes for a node are rendered
33912 * @param {Node} node The node
33914 "beforechildrenrendered":true,
33917 * Fires when a node starts being dragged
33918 * @param {Roo.tree.TreePanel} this
33919 * @param {Roo.tree.TreeNode} node
33920 * @param {event} e The raw browser event
33922 "startdrag" : true,
33925 * Fires when a drag operation is complete
33926 * @param {Roo.tree.TreePanel} this
33927 * @param {Roo.tree.TreeNode} node
33928 * @param {event} e The raw browser event
33933 * Fires when a dragged node is dropped on a valid DD target
33934 * @param {Roo.tree.TreePanel} this
33935 * @param {Roo.tree.TreeNode} node
33936 * @param {DD} dd The dd it was dropped on
33937 * @param {event} e The raw browser event
33941 * @event beforenodedrop
33942 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
33943 * passed to handlers has the following properties:<br />
33944 * <ul style="padding:5px;padding-left:16px;">
33945 * <li>tree - The TreePanel</li>
33946 * <li>target - The node being targeted for the drop</li>
33947 * <li>data - The drag data from the drag source</li>
33948 * <li>point - The point of the drop - append, above or below</li>
33949 * <li>source - The drag source</li>
33950 * <li>rawEvent - Raw mouse event</li>
33951 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
33952 * to be inserted by setting them on this object.</li>
33953 * <li>cancel - Set this to true to cancel the drop.</li>
33955 * @param {Object} dropEvent
33957 "beforenodedrop" : true,
33960 * Fires after a DD object is dropped on a node in this tree. The dropEvent
33961 * passed to handlers has the following properties:<br />
33962 * <ul style="padding:5px;padding-left:16px;">
33963 * <li>tree - The TreePanel</li>
33964 * <li>target - The node being targeted for the drop</li>
33965 * <li>data - The drag data from the drag source</li>
33966 * <li>point - The point of the drop - append, above or below</li>
33967 * <li>source - The drag source</li>
33968 * <li>rawEvent - Raw mouse event</li>
33969 * <li>dropNode - Dropped node(s).</li>
33971 * @param {Object} dropEvent
33975 * @event nodedragover
33976 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
33977 * passed to handlers has the following properties:<br />
33978 * <ul style="padding:5px;padding-left:16px;">
33979 * <li>tree - The TreePanel</li>
33980 * <li>target - The node being targeted for the drop</li>
33981 * <li>data - The drag data from the drag source</li>
33982 * <li>point - The point of the drop - append, above or below</li>
33983 * <li>source - The drag source</li>
33984 * <li>rawEvent - Raw mouse event</li>
33985 * <li>dropNode - Drop node(s) provided by the source.</li>
33986 * <li>cancel - Set this to true to signal drop not allowed.</li>
33988 * @param {Object} dragOverEvent
33990 "nodedragover" : true
33993 if(this.singleExpand){
33994 this.on("beforeexpand", this.restrictExpand, this);
33997 this.editor.tree = this;
33998 this.editor = Roo.factory(this.editor, Roo.tree);
34001 if (this.selModel) {
34002 this.selModel = Roo.factory(this.selModel, Roo.tree);
34006 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34007 rootVisible : true,
34008 animate: Roo.enableFx,
34011 hlDrop : Roo.enableFx,
34015 rendererTip: false,
34017 restrictExpand : function(node){
34018 var p = node.parentNode;
34020 if(p.expandedChild && p.expandedChild.parentNode == p){
34021 p.expandedChild.collapse();
34023 p.expandedChild = node;
34027 // private override
34028 setRootNode : function(node){
34029 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34030 if(!this.rootVisible){
34031 node.ui = new Roo.tree.RootTreeNodeUI(node);
34037 * Returns the container element for this TreePanel
34039 getEl : function(){
34044 * Returns the default TreeLoader for this TreePanel
34046 getLoader : function(){
34047 return this.loader;
34053 expandAll : function(){
34054 this.root.expand(true);
34058 * Collapse all nodes
34060 collapseAll : function(){
34061 this.root.collapse(true);
34065 * Returns the selection model used by this TreePanel
34067 getSelectionModel : function(){
34068 if(!this.selModel){
34069 this.selModel = new Roo.tree.DefaultSelectionModel();
34071 return this.selModel;
34075 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34076 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34077 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34080 getChecked : function(a, startNode){
34081 startNode = startNode || this.root;
34083 var f = function(){
34084 if(this.attributes.checked){
34085 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34088 startNode.cascade(f);
34093 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34094 * @param {String} path
34095 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34096 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34097 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34099 expandPath : function(path, attr, callback){
34100 attr = attr || "id";
34101 var keys = path.split(this.pathSeparator);
34102 var curNode = this.root;
34103 if(curNode.attributes[attr] != keys[1]){ // invalid root
34105 callback(false, null);
34110 var f = function(){
34111 if(++index == keys.length){
34113 callback(true, curNode);
34117 var c = curNode.findChild(attr, keys[index]);
34120 callback(false, curNode);
34125 c.expand(false, false, f);
34127 curNode.expand(false, false, f);
34131 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34132 * @param {String} path
34133 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34134 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34135 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34137 selectPath : function(path, attr, callback){
34138 attr = attr || "id";
34139 var keys = path.split(this.pathSeparator);
34140 var v = keys.pop();
34141 if(keys.length > 0){
34142 var f = function(success, node){
34143 if(success && node){
34144 var n = node.findChild(attr, v);
34150 }else if(callback){
34151 callback(false, n);
34155 callback(false, n);
34159 this.expandPath(keys.join(this.pathSeparator), attr, f);
34161 this.root.select();
34163 callback(true, this.root);
34168 getTreeEl : function(){
34173 * Trigger rendering of this TreePanel
34175 render : function(){
34176 if (this.innerCt) {
34177 return this; // stop it rendering more than once!!
34180 this.innerCt = this.el.createChild({tag:"ul",
34181 cls:"x-tree-root-ct " +
34182 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34184 if(this.containerScroll){
34185 Roo.dd.ScrollManager.register(this.el);
34187 if((this.enableDD || this.enableDrop) && !this.dropZone){
34189 * The dropZone used by this tree if drop is enabled
34190 * @type Roo.tree.TreeDropZone
34192 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34193 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34196 if((this.enableDD || this.enableDrag) && !this.dragZone){
34198 * The dragZone used by this tree if drag is enabled
34199 * @type Roo.tree.TreeDragZone
34201 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34202 ddGroup: this.ddGroup || "TreeDD",
34203 scroll: this.ddScroll
34206 this.getSelectionModel().init(this);
34208 Roo.log("ROOT not set in tree");
34211 this.root.render();
34212 if(!this.rootVisible){
34213 this.root.renderChildren();
34219 * Ext JS Library 1.1.1
34220 * Copyright(c) 2006-2007, Ext JS, LLC.
34222 * Originally Released Under LGPL - original licence link has changed is not relivant.
34225 * <script type="text/javascript">
34230 * @class Roo.tree.DefaultSelectionModel
34231 * @extends Roo.util.Observable
34232 * The default single selection for a TreePanel.
34233 * @param {Object} cfg Configuration
34235 Roo.tree.DefaultSelectionModel = function(cfg){
34236 this.selNode = null;
34242 * @event selectionchange
34243 * Fires when the selected node changes
34244 * @param {DefaultSelectionModel} this
34245 * @param {TreeNode} node the new selection
34247 "selectionchange" : true,
34250 * @event beforeselect
34251 * Fires before the selected node changes, return false to cancel the change
34252 * @param {DefaultSelectionModel} this
34253 * @param {TreeNode} node the new selection
34254 * @param {TreeNode} node the old selection
34256 "beforeselect" : true
34259 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34262 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34263 init : function(tree){
34265 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34266 tree.on("click", this.onNodeClick, this);
34269 onNodeClick : function(node, e){
34270 if (e.ctrlKey && this.selNode == node) {
34271 this.unselect(node);
34279 * @param {TreeNode} node The node to select
34280 * @return {TreeNode} The selected node
34282 select : function(node){
34283 var last = this.selNode;
34284 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34286 last.ui.onSelectedChange(false);
34288 this.selNode = node;
34289 node.ui.onSelectedChange(true);
34290 this.fireEvent("selectionchange", this, node, last);
34297 * @param {TreeNode} node The node to unselect
34299 unselect : function(node){
34300 if(this.selNode == node){
34301 this.clearSelections();
34306 * Clear all selections
34308 clearSelections : function(){
34309 var n = this.selNode;
34311 n.ui.onSelectedChange(false);
34312 this.selNode = null;
34313 this.fireEvent("selectionchange", this, null);
34319 * Get the selected node
34320 * @return {TreeNode} The selected node
34322 getSelectedNode : function(){
34323 return this.selNode;
34327 * Returns true if the node is selected
34328 * @param {TreeNode} node The node to check
34329 * @return {Boolean}
34331 isSelected : function(node){
34332 return this.selNode == node;
34336 * Selects the node above the selected node in the tree, intelligently walking the nodes
34337 * @return TreeNode The new selection
34339 selectPrevious : function(){
34340 var s = this.selNode || this.lastSelNode;
34344 var ps = s.previousSibling;
34346 if(!ps.isExpanded() || ps.childNodes.length < 1){
34347 return this.select(ps);
34349 var lc = ps.lastChild;
34350 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34353 return this.select(lc);
34355 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34356 return this.select(s.parentNode);
34362 * Selects the node above the selected node in the tree, intelligently walking the nodes
34363 * @return TreeNode The new selection
34365 selectNext : function(){
34366 var s = this.selNode || this.lastSelNode;
34370 if(s.firstChild && s.isExpanded()){
34371 return this.select(s.firstChild);
34372 }else if(s.nextSibling){
34373 return this.select(s.nextSibling);
34374 }else if(s.parentNode){
34376 s.parentNode.bubble(function(){
34377 if(this.nextSibling){
34378 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34387 onKeyDown : function(e){
34388 var s = this.selNode || this.lastSelNode;
34389 // undesirable, but required
34394 var k = e.getKey();
34402 this.selectPrevious();
34405 e.preventDefault();
34406 if(s.hasChildNodes()){
34407 if(!s.isExpanded()){
34409 }else if(s.firstChild){
34410 this.select(s.firstChild, e);
34415 e.preventDefault();
34416 if(s.hasChildNodes() && s.isExpanded()){
34418 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34419 this.select(s.parentNode, e);
34427 * @class Roo.tree.MultiSelectionModel
34428 * @extends Roo.util.Observable
34429 * Multi selection for a TreePanel.
34430 * @param {Object} cfg Configuration
34432 Roo.tree.MultiSelectionModel = function(){
34433 this.selNodes = [];
34437 * @event selectionchange
34438 * Fires when the selected nodes change
34439 * @param {MultiSelectionModel} this
34440 * @param {Array} nodes Array of the selected nodes
34442 "selectionchange" : true
34444 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34448 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34449 init : function(tree){
34451 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34452 tree.on("click", this.onNodeClick, this);
34455 onNodeClick : function(node, e){
34456 this.select(node, e, e.ctrlKey);
34461 * @param {TreeNode} node The node to select
34462 * @param {EventObject} e (optional) An event associated with the selection
34463 * @param {Boolean} keepExisting True to retain existing selections
34464 * @return {TreeNode} The selected node
34466 select : function(node, e, keepExisting){
34467 if(keepExisting !== true){
34468 this.clearSelections(true);
34470 if(this.isSelected(node)){
34471 this.lastSelNode = node;
34474 this.selNodes.push(node);
34475 this.selMap[node.id] = node;
34476 this.lastSelNode = node;
34477 node.ui.onSelectedChange(true);
34478 this.fireEvent("selectionchange", this, this.selNodes);
34484 * @param {TreeNode} node The node to unselect
34486 unselect : function(node){
34487 if(this.selMap[node.id]){
34488 node.ui.onSelectedChange(false);
34489 var sn = this.selNodes;
34492 index = sn.indexOf(node);
34494 for(var i = 0, len = sn.length; i < len; i++){
34502 this.selNodes.splice(index, 1);
34504 delete this.selMap[node.id];
34505 this.fireEvent("selectionchange", this, this.selNodes);
34510 * Clear all selections
34512 clearSelections : function(suppressEvent){
34513 var sn = this.selNodes;
34515 for(var i = 0, len = sn.length; i < len; i++){
34516 sn[i].ui.onSelectedChange(false);
34518 this.selNodes = [];
34520 if(suppressEvent !== true){
34521 this.fireEvent("selectionchange", this, this.selNodes);
34527 * Returns true if the node is selected
34528 * @param {TreeNode} node The node to check
34529 * @return {Boolean}
34531 isSelected : function(node){
34532 return this.selMap[node.id] ? true : false;
34536 * Returns an array of the selected nodes
34539 getSelectedNodes : function(){
34540 return this.selNodes;
34543 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34545 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34547 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34550 * Ext JS Library 1.1.1
34551 * Copyright(c) 2006-2007, Ext JS, LLC.
34553 * Originally Released Under LGPL - original licence link has changed is not relivant.
34556 * <script type="text/javascript">
34560 * @class Roo.tree.TreeNode
34561 * @extends Roo.data.Node
34562 * @cfg {String} text The text for this node
34563 * @cfg {Boolean} expanded true to start the node expanded
34564 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34565 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34566 * @cfg {Boolean} disabled true to start the node disabled
34567 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34568 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34569 * @cfg {String} cls A css class to be added to the node
34570 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34571 * @cfg {String} href URL of the link used for the node (defaults to #)
34572 * @cfg {String} hrefTarget target frame for the link
34573 * @cfg {String} qtip An Ext QuickTip for the node
34574 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34575 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34576 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34577 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34578 * (defaults to undefined with no checkbox rendered)
34580 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34582 Roo.tree.TreeNode = function(attributes){
34583 attributes = attributes || {};
34584 if(typeof attributes == "string"){
34585 attributes = {text: attributes};
34587 this.childrenRendered = false;
34588 this.rendered = false;
34589 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34590 this.expanded = attributes.expanded === true;
34591 this.isTarget = attributes.isTarget !== false;
34592 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34593 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34596 * Read-only. The text for this node. To change it use setText().
34599 this.text = attributes.text;
34601 * True if this node is disabled.
34604 this.disabled = attributes.disabled === true;
34608 * @event textchange
34609 * Fires when the text for this node is changed
34610 * @param {Node} this This node
34611 * @param {String} text The new text
34612 * @param {String} oldText The old text
34614 "textchange" : true,
34616 * @event beforeexpand
34617 * Fires before this node is expanded, return false to cancel.
34618 * @param {Node} this This node
34619 * @param {Boolean} deep
34620 * @param {Boolean} anim
34622 "beforeexpand" : true,
34624 * @event beforecollapse
34625 * Fires before this node is collapsed, return false to cancel.
34626 * @param {Node} this This node
34627 * @param {Boolean} deep
34628 * @param {Boolean} anim
34630 "beforecollapse" : true,
34633 * Fires when this node is expanded
34634 * @param {Node} this This node
34638 * @event disabledchange
34639 * Fires when the disabled status of this node changes
34640 * @param {Node} this This node
34641 * @param {Boolean} disabled
34643 "disabledchange" : true,
34646 * Fires when this node is collapsed
34647 * @param {Node} this This node
34651 * @event beforeclick
34652 * Fires before click processing. Return false to cancel the default action.
34653 * @param {Node} this This node
34654 * @param {Roo.EventObject} e The event object
34656 "beforeclick":true,
34658 * @event checkchange
34659 * Fires when a node with a checkbox's checked property changes
34660 * @param {Node} this This node
34661 * @param {Boolean} checked
34663 "checkchange":true,
34666 * Fires when this node is clicked
34667 * @param {Node} this This node
34668 * @param {Roo.EventObject} e The event object
34673 * Fires when this node is double clicked
34674 * @param {Node} this This node
34675 * @param {Roo.EventObject} e The event object
34679 * @event contextmenu
34680 * Fires when this node is right clicked
34681 * @param {Node} this This node
34682 * @param {Roo.EventObject} e The event object
34684 "contextmenu":true,
34686 * @event beforechildrenrendered
34687 * Fires right before the child nodes for this node are rendered
34688 * @param {Node} this This node
34690 "beforechildrenrendered":true
34693 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34696 * Read-only. The UI for this node
34699 this.ui = new uiClass(this);
34701 // finally support items[]
34702 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34707 Roo.each(this.attributes.items, function(c) {
34708 this.appendChild(Roo.factory(c,Roo.Tree));
34710 delete this.attributes.items;
34715 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34716 preventHScroll: true,
34718 * Returns true if this node is expanded
34719 * @return {Boolean}
34721 isExpanded : function(){
34722 return this.expanded;
34726 * Returns the UI object for this node
34727 * @return {TreeNodeUI}
34729 getUI : function(){
34733 // private override
34734 setFirstChild : function(node){
34735 var of = this.firstChild;
34736 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34737 if(this.childrenRendered && of && node != of){
34738 of.renderIndent(true, true);
34741 this.renderIndent(true, true);
34745 // private override
34746 setLastChild : function(node){
34747 var ol = this.lastChild;
34748 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34749 if(this.childrenRendered && ol && node != ol){
34750 ol.renderIndent(true, true);
34753 this.renderIndent(true, true);
34757 // these methods are overridden to provide lazy rendering support
34758 // private override
34759 appendChild : function()
34761 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34762 if(node && this.childrenRendered){
34765 this.ui.updateExpandIcon();
34769 // private override
34770 removeChild : function(node){
34771 this.ownerTree.getSelectionModel().unselect(node);
34772 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34773 // if it's been rendered remove dom node
34774 if(this.childrenRendered){
34777 if(this.childNodes.length < 1){
34778 this.collapse(false, false);
34780 this.ui.updateExpandIcon();
34782 if(!this.firstChild) {
34783 this.childrenRendered = false;
34788 // private override
34789 insertBefore : function(node, refNode){
34790 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34791 if(newNode && refNode && this.childrenRendered){
34794 this.ui.updateExpandIcon();
34799 * Sets the text for this node
34800 * @param {String} text
34802 setText : function(text){
34803 var oldText = this.text;
34805 this.attributes.text = text;
34806 if(this.rendered){ // event without subscribing
34807 this.ui.onTextChange(this, text, oldText);
34809 this.fireEvent("textchange", this, text, oldText);
34813 * Triggers selection of this node
34815 select : function(){
34816 this.getOwnerTree().getSelectionModel().select(this);
34820 * Triggers deselection of this node
34822 unselect : function(){
34823 this.getOwnerTree().getSelectionModel().unselect(this);
34827 * Returns true if this node is selected
34828 * @return {Boolean}
34830 isSelected : function(){
34831 return this.getOwnerTree().getSelectionModel().isSelected(this);
34835 * Expand this node.
34836 * @param {Boolean} deep (optional) True to expand all children as well
34837 * @param {Boolean} anim (optional) false to cancel the default animation
34838 * @param {Function} callback (optional) A callback to be called when
34839 * expanding this node completes (does not wait for deep expand to complete).
34840 * Called with 1 parameter, this node.
34842 expand : function(deep, anim, callback){
34843 if(!this.expanded){
34844 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
34847 if(!this.childrenRendered){
34848 this.renderChildren();
34850 this.expanded = true;
34851 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
34852 this.ui.animExpand(function(){
34853 this.fireEvent("expand", this);
34854 if(typeof callback == "function"){
34858 this.expandChildNodes(true);
34860 }.createDelegate(this));
34864 this.fireEvent("expand", this);
34865 if(typeof callback == "function"){
34870 if(typeof callback == "function"){
34875 this.expandChildNodes(true);
34879 isHiddenRoot : function(){
34880 return this.isRoot && !this.getOwnerTree().rootVisible;
34884 * Collapse this node.
34885 * @param {Boolean} deep (optional) True to collapse all children as well
34886 * @param {Boolean} anim (optional) false to cancel the default animation
34888 collapse : function(deep, anim){
34889 if(this.expanded && !this.isHiddenRoot()){
34890 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
34893 this.expanded = false;
34894 if((this.getOwnerTree().animate && anim !== false) || anim){
34895 this.ui.animCollapse(function(){
34896 this.fireEvent("collapse", this);
34898 this.collapseChildNodes(true);
34900 }.createDelegate(this));
34903 this.ui.collapse();
34904 this.fireEvent("collapse", this);
34908 var cs = this.childNodes;
34909 for(var i = 0, len = cs.length; i < len; i++) {
34910 cs[i].collapse(true, false);
34916 delayedExpand : function(delay){
34917 if(!this.expandProcId){
34918 this.expandProcId = this.expand.defer(delay, this);
34923 cancelExpand : function(){
34924 if(this.expandProcId){
34925 clearTimeout(this.expandProcId);
34927 this.expandProcId = false;
34931 * Toggles expanded/collapsed state of the node
34933 toggle : function(){
34942 * Ensures all parent nodes are expanded
34944 ensureVisible : function(callback){
34945 var tree = this.getOwnerTree();
34946 tree.expandPath(this.parentNode.getPath(), false, function(){
34947 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
34948 Roo.callback(callback);
34949 }.createDelegate(this));
34953 * Expand all child nodes
34954 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
34956 expandChildNodes : function(deep){
34957 var cs = this.childNodes;
34958 for(var i = 0, len = cs.length; i < len; i++) {
34959 cs[i].expand(deep);
34964 * Collapse all child nodes
34965 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
34967 collapseChildNodes : function(deep){
34968 var cs = this.childNodes;
34969 for(var i = 0, len = cs.length; i < len; i++) {
34970 cs[i].collapse(deep);
34975 * Disables this node
34977 disable : function(){
34978 this.disabled = true;
34980 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
34981 this.ui.onDisableChange(this, true);
34983 this.fireEvent("disabledchange", this, true);
34987 * Enables this node
34989 enable : function(){
34990 this.disabled = false;
34991 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
34992 this.ui.onDisableChange(this, false);
34994 this.fireEvent("disabledchange", this, false);
34998 renderChildren : function(suppressEvent){
34999 if(suppressEvent !== false){
35000 this.fireEvent("beforechildrenrendered", this);
35002 var cs = this.childNodes;
35003 for(var i = 0, len = cs.length; i < len; i++){
35004 cs[i].render(true);
35006 this.childrenRendered = true;
35010 sort : function(fn, scope){
35011 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35012 if(this.childrenRendered){
35013 var cs = this.childNodes;
35014 for(var i = 0, len = cs.length; i < len; i++){
35015 cs[i].render(true);
35021 render : function(bulkRender){
35022 this.ui.render(bulkRender);
35023 if(!this.rendered){
35024 this.rendered = true;
35026 this.expanded = false;
35027 this.expand(false, false);
35033 renderIndent : function(deep, refresh){
35035 this.ui.childIndent = null;
35037 this.ui.renderIndent();
35038 if(deep === true && this.childrenRendered){
35039 var cs = this.childNodes;
35040 for(var i = 0, len = cs.length; i < len; i++){
35041 cs[i].renderIndent(true, refresh);
35047 * Ext JS Library 1.1.1
35048 * Copyright(c) 2006-2007, Ext JS, LLC.
35050 * Originally Released Under LGPL - original licence link has changed is not relivant.
35053 * <script type="text/javascript">
35057 * @class Roo.tree.AsyncTreeNode
35058 * @extends Roo.tree.TreeNode
35059 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35061 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35063 Roo.tree.AsyncTreeNode = function(config){
35064 this.loaded = false;
35065 this.loading = false;
35066 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35068 * @event beforeload
35069 * Fires before this node is loaded, return false to cancel
35070 * @param {Node} this This node
35072 this.addEvents({'beforeload':true, 'load': true});
35075 * Fires when this node is loaded
35076 * @param {Node} this This node
35079 * The loader used by this node (defaults to using the tree's defined loader)
35084 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35085 expand : function(deep, anim, callback){
35086 if(this.loading){ // if an async load is already running, waiting til it's done
35088 var f = function(){
35089 if(!this.loading){ // done loading
35090 clearInterval(timer);
35091 this.expand(deep, anim, callback);
35093 }.createDelegate(this);
35094 timer = setInterval(f, 200);
35098 if(this.fireEvent("beforeload", this) === false){
35101 this.loading = true;
35102 this.ui.beforeLoad(this);
35103 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35105 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35109 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35113 * Returns true if this node is currently loading
35114 * @return {Boolean}
35116 isLoading : function(){
35117 return this.loading;
35120 loadComplete : function(deep, anim, callback){
35121 this.loading = false;
35122 this.loaded = true;
35123 this.ui.afterLoad(this);
35124 this.fireEvent("load", this);
35125 this.expand(deep, anim, callback);
35129 * Returns true if this node has been loaded
35130 * @return {Boolean}
35132 isLoaded : function(){
35133 return this.loaded;
35136 hasChildNodes : function(){
35137 if(!this.isLeaf() && !this.loaded){
35140 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35145 * Trigger a reload for this node
35146 * @param {Function} callback
35148 reload : function(callback){
35149 this.collapse(false, false);
35150 while(this.firstChild){
35151 this.removeChild(this.firstChild);
35153 this.childrenRendered = false;
35154 this.loaded = false;
35155 if(this.isHiddenRoot()){
35156 this.expanded = false;
35158 this.expand(false, false, callback);
35162 * Ext JS Library 1.1.1
35163 * Copyright(c) 2006-2007, Ext JS, LLC.
35165 * Originally Released Under LGPL - original licence link has changed is not relivant.
35168 * <script type="text/javascript">
35172 * @class Roo.tree.TreeNodeUI
35174 * @param {Object} node The node to render
35175 * The TreeNode UI implementation is separate from the
35176 * tree implementation. Unless you are customizing the tree UI,
35177 * you should never have to use this directly.
35179 Roo.tree.TreeNodeUI = function(node){
35181 this.rendered = false;
35182 this.animating = false;
35183 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35186 Roo.tree.TreeNodeUI.prototype = {
35187 removeChild : function(node){
35189 this.ctNode.removeChild(node.ui.getEl());
35193 beforeLoad : function(){
35194 this.addClass("x-tree-node-loading");
35197 afterLoad : function(){
35198 this.removeClass("x-tree-node-loading");
35201 onTextChange : function(node, text, oldText){
35203 this.textNode.innerHTML = text;
35207 onDisableChange : function(node, state){
35208 this.disabled = state;
35210 this.addClass("x-tree-node-disabled");
35212 this.removeClass("x-tree-node-disabled");
35216 onSelectedChange : function(state){
35219 this.addClass("x-tree-selected");
35222 this.removeClass("x-tree-selected");
35226 onMove : function(tree, node, oldParent, newParent, index, refNode){
35227 this.childIndent = null;
35229 var targetNode = newParent.ui.getContainer();
35230 if(!targetNode){//target not rendered
35231 this.holder = document.createElement("div");
35232 this.holder.appendChild(this.wrap);
35235 var insertBefore = refNode ? refNode.ui.getEl() : null;
35237 targetNode.insertBefore(this.wrap, insertBefore);
35239 targetNode.appendChild(this.wrap);
35241 this.node.renderIndent(true);
35245 addClass : function(cls){
35247 Roo.fly(this.elNode).addClass(cls);
35251 removeClass : function(cls){
35253 Roo.fly(this.elNode).removeClass(cls);
35257 remove : function(){
35259 this.holder = document.createElement("div");
35260 this.holder.appendChild(this.wrap);
35264 fireEvent : function(){
35265 return this.node.fireEvent.apply(this.node, arguments);
35268 initEvents : function(){
35269 this.node.on("move", this.onMove, this);
35270 var E = Roo.EventManager;
35271 var a = this.anchor;
35273 var el = Roo.fly(a, '_treeui');
35275 if(Roo.isOpera){ // opera render bug ignores the CSS
35276 el.setStyle("text-decoration", "none");
35279 el.on("click", this.onClick, this);
35280 el.on("dblclick", this.onDblClick, this);
35283 Roo.EventManager.on(this.checkbox,
35284 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35287 el.on("contextmenu", this.onContextMenu, this);
35289 var icon = Roo.fly(this.iconNode);
35290 icon.on("click", this.onClick, this);
35291 icon.on("dblclick", this.onDblClick, this);
35292 icon.on("contextmenu", this.onContextMenu, this);
35293 E.on(this.ecNode, "click", this.ecClick, this, true);
35295 if(this.node.disabled){
35296 this.addClass("x-tree-node-disabled");
35298 if(this.node.hidden){
35299 this.addClass("x-tree-node-disabled");
35301 var ot = this.node.getOwnerTree();
35302 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35303 if(dd && (!this.node.isRoot || ot.rootVisible)){
35304 Roo.dd.Registry.register(this.elNode, {
35306 handles: this.getDDHandles(),
35312 getDDHandles : function(){
35313 return [this.iconNode, this.textNode];
35318 this.wrap.style.display = "none";
35324 this.wrap.style.display = "";
35328 onContextMenu : function(e){
35329 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35330 e.preventDefault();
35332 this.fireEvent("contextmenu", this.node, e);
35336 onClick : function(e){
35341 if(this.fireEvent("beforeclick", this.node, e) !== false){
35342 if(!this.disabled && this.node.attributes.href){
35343 this.fireEvent("click", this.node, e);
35346 e.preventDefault();
35351 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35352 this.node.toggle();
35355 this.fireEvent("click", this.node, e);
35361 onDblClick : function(e){
35362 e.preventDefault();
35367 this.toggleCheck();
35369 if(!this.animating && this.node.hasChildNodes()){
35370 this.node.toggle();
35372 this.fireEvent("dblclick", this.node, e);
35375 onCheckChange : function(){
35376 var checked = this.checkbox.checked;
35377 this.node.attributes.checked = checked;
35378 this.fireEvent('checkchange', this.node, checked);
35381 ecClick : function(e){
35382 if(!this.animating && this.node.hasChildNodes()){
35383 this.node.toggle();
35387 startDrop : function(){
35388 this.dropping = true;
35391 // delayed drop so the click event doesn't get fired on a drop
35392 endDrop : function(){
35393 setTimeout(function(){
35394 this.dropping = false;
35395 }.createDelegate(this), 50);
35398 expand : function(){
35399 this.updateExpandIcon();
35400 this.ctNode.style.display = "";
35403 focus : function(){
35404 if(!this.node.preventHScroll){
35405 try{this.anchor.focus();
35407 }else if(!Roo.isIE){
35409 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35410 var l = noscroll.scrollLeft;
35411 this.anchor.focus();
35412 noscroll.scrollLeft = l;
35417 toggleCheck : function(value){
35418 var cb = this.checkbox;
35420 cb.checked = (value === undefined ? !cb.checked : value);
35426 this.anchor.blur();
35430 animExpand : function(callback){
35431 var ct = Roo.get(this.ctNode);
35433 if(!this.node.hasChildNodes()){
35434 this.updateExpandIcon();
35435 this.ctNode.style.display = "";
35436 Roo.callback(callback);
35439 this.animating = true;
35440 this.updateExpandIcon();
35443 callback : function(){
35444 this.animating = false;
35445 Roo.callback(callback);
35448 duration: this.node.ownerTree.duration || .25
35452 highlight : function(){
35453 var tree = this.node.getOwnerTree();
35454 Roo.fly(this.wrap).highlight(
35455 tree.hlColor || "C3DAF9",
35456 {endColor: tree.hlBaseColor}
35460 collapse : function(){
35461 this.updateExpandIcon();
35462 this.ctNode.style.display = "none";
35465 animCollapse : function(callback){
35466 var ct = Roo.get(this.ctNode);
35467 ct.enableDisplayMode('block');
35470 this.animating = true;
35471 this.updateExpandIcon();
35474 callback : function(){
35475 this.animating = false;
35476 Roo.callback(callback);
35479 duration: this.node.ownerTree.duration || .25
35483 getContainer : function(){
35484 return this.ctNode;
35487 getEl : function(){
35491 appendDDGhost : function(ghostNode){
35492 ghostNode.appendChild(this.elNode.cloneNode(true));
35495 getDDRepairXY : function(){
35496 return Roo.lib.Dom.getXY(this.iconNode);
35499 onRender : function(){
35503 render : function(bulkRender){
35504 var n = this.node, a = n.attributes;
35505 var targetNode = n.parentNode ?
35506 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35508 if(!this.rendered){
35509 this.rendered = true;
35511 this.renderElements(n, a, targetNode, bulkRender);
35514 if(this.textNode.setAttributeNS){
35515 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35517 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35520 this.textNode.setAttribute("ext:qtip", a.qtip);
35522 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35525 }else if(a.qtipCfg){
35526 a.qtipCfg.target = Roo.id(this.textNode);
35527 Roo.QuickTips.register(a.qtipCfg);
35530 if(!this.node.expanded){
35531 this.updateExpandIcon();
35534 if(bulkRender === true) {
35535 targetNode.appendChild(this.wrap);
35540 renderElements : function(n, a, targetNode, bulkRender)
35542 // add some indent caching, this helps performance when rendering a large tree
35543 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35544 var t = n.getOwnerTree();
35545 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35546 if (typeof(n.attributes.html) != 'undefined') {
35547 txt = n.attributes.html;
35549 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35550 var cb = typeof a.checked == 'boolean';
35551 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35552 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35553 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35554 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35555 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35556 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35557 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35558 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35559 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35560 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35563 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35564 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35565 n.nextSibling.ui.getEl(), buf.join(""));
35567 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35570 this.elNode = this.wrap.childNodes[0];
35571 this.ctNode = this.wrap.childNodes[1];
35572 var cs = this.elNode.childNodes;
35573 this.indentNode = cs[0];
35574 this.ecNode = cs[1];
35575 this.iconNode = cs[2];
35578 this.checkbox = cs[3];
35581 this.anchor = cs[index];
35582 this.textNode = cs[index].firstChild;
35585 getAnchor : function(){
35586 return this.anchor;
35589 getTextEl : function(){
35590 return this.textNode;
35593 getIconEl : function(){
35594 return this.iconNode;
35597 isChecked : function(){
35598 return this.checkbox ? this.checkbox.checked : false;
35601 updateExpandIcon : function(){
35603 var n = this.node, c1, c2;
35604 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35605 var hasChild = n.hasChildNodes();
35609 c1 = "x-tree-node-collapsed";
35610 c2 = "x-tree-node-expanded";
35613 c1 = "x-tree-node-expanded";
35614 c2 = "x-tree-node-collapsed";
35617 this.removeClass("x-tree-node-leaf");
35618 this.wasLeaf = false;
35620 if(this.c1 != c1 || this.c2 != c2){
35621 Roo.fly(this.elNode).replaceClass(c1, c2);
35622 this.c1 = c1; this.c2 = c2;
35625 // this changes non-leafs into leafs if they have no children.
35626 // it's not very rational behaviour..
35628 if(!this.wasLeaf && this.node.leaf){
35629 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35632 this.wasLeaf = true;
35635 var ecc = "x-tree-ec-icon "+cls;
35636 if(this.ecc != ecc){
35637 this.ecNode.className = ecc;
35643 getChildIndent : function(){
35644 if(!this.childIndent){
35648 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35650 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35652 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35657 this.childIndent = buf.join("");
35659 return this.childIndent;
35662 renderIndent : function(){
35665 var p = this.node.parentNode;
35667 indent = p.ui.getChildIndent();
35669 if(this.indentMarkup != indent){ // don't rerender if not required
35670 this.indentNode.innerHTML = indent;
35671 this.indentMarkup = indent;
35673 this.updateExpandIcon();
35678 Roo.tree.RootTreeNodeUI = function(){
35679 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35681 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35682 render : function(){
35683 if(!this.rendered){
35684 var targetNode = this.node.ownerTree.innerCt.dom;
35685 this.node.expanded = true;
35686 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35687 this.wrap = this.ctNode = targetNode.firstChild;
35690 collapse : function(){
35692 expand : function(){
35696 * Ext JS Library 1.1.1
35697 * Copyright(c) 2006-2007, Ext JS, LLC.
35699 * Originally Released Under LGPL - original licence link has changed is not relivant.
35702 * <script type="text/javascript">
35705 * @class Roo.tree.TreeLoader
35706 * @extends Roo.util.Observable
35707 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35708 * nodes from a specified URL. The response must be a javascript Array definition
35709 * who's elements are node definition objects. eg:
35714 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35715 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35722 * The old style respose with just an array is still supported, but not recommended.
35725 * A server request is sent, and child nodes are loaded only when a node is expanded.
35726 * The loading node's id is passed to the server under the parameter name "node" to
35727 * enable the server to produce the correct child nodes.
35729 * To pass extra parameters, an event handler may be attached to the "beforeload"
35730 * event, and the parameters specified in the TreeLoader's baseParams property:
35732 myTreeLoader.on("beforeload", function(treeLoader, node) {
35733 this.baseParams.category = node.attributes.category;
35736 * This would pass an HTTP parameter called "category" to the server containing
35737 * the value of the Node's "category" attribute.
35739 * Creates a new Treeloader.
35740 * @param {Object} config A config object containing config properties.
35742 Roo.tree.TreeLoader = function(config){
35743 this.baseParams = {};
35744 this.requestMethod = "POST";
35745 Roo.apply(this, config);
35750 * @event beforeload
35751 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35752 * @param {Object} This TreeLoader object.
35753 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35754 * @param {Object} callback The callback function specified in the {@link #load} call.
35759 * Fires when the node has been successfuly loaded.
35760 * @param {Object} This TreeLoader object.
35761 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35762 * @param {Object} response The response object containing the data from the server.
35766 * @event loadexception
35767 * Fires if the network request failed.
35768 * @param {Object} This TreeLoader object.
35769 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35770 * @param {Object} response The response object containing the data from the server.
35772 loadexception : true,
35775 * Fires before a node is created, enabling you to return custom Node types
35776 * @param {Object} This TreeLoader object.
35777 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35782 Roo.tree.TreeLoader.superclass.constructor.call(this);
35785 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35787 * @cfg {String} dataUrl The URL from which to request a Json string which
35788 * specifies an array of node definition object representing the child nodes
35792 * @cfg {String} requestMethod either GET or POST
35793 * defaults to POST (due to BC)
35797 * @cfg {Object} baseParams (optional) An object containing properties which
35798 * specify HTTP parameters to be passed to each request for child nodes.
35801 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35802 * created by this loader. If the attributes sent by the server have an attribute in this object,
35803 * they take priority.
35806 * @cfg {Object} uiProviders (optional) An object containing properties which
35808 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35809 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35810 * <i>uiProvider</i> attribute of a returned child node is a string rather
35811 * than a reference to a TreeNodeUI implementation, this that string value
35812 * is used as a property name in the uiProviders object. You can define the provider named
35813 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35818 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35819 * child nodes before loading.
35821 clearOnLoad : true,
35824 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35825 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35826 * Grid query { data : [ .....] }
35831 * @cfg {String} queryParam (optional)
35832 * Name of the query as it will be passed on the querystring (defaults to 'node')
35833 * eg. the request will be ?node=[id]
35840 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35841 * This is called automatically when a node is expanded, but may be used to reload
35842 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35843 * @param {Roo.tree.TreeNode} node
35844 * @param {Function} callback
35846 load : function(node, callback){
35847 if(this.clearOnLoad){
35848 while(node.firstChild){
35849 node.removeChild(node.firstChild);
35852 if(node.attributes.children){ // preloaded json children
35853 var cs = node.attributes.children;
35854 for(var i = 0, len = cs.length; i < len; i++){
35855 node.appendChild(this.createNode(cs[i]));
35857 if(typeof callback == "function"){
35860 }else if(this.dataUrl){
35861 this.requestData(node, callback);
35865 getParams: function(node){
35866 var buf = [], bp = this.baseParams;
35867 for(var key in bp){
35868 if(typeof bp[key] != "function"){
35869 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
35872 var n = this.queryParam === false ? 'node' : this.queryParam;
35873 buf.push(n + "=", encodeURIComponent(node.id));
35874 return buf.join("");
35877 requestData : function(node, callback){
35878 if(this.fireEvent("beforeload", this, node, callback) !== false){
35879 this.transId = Roo.Ajax.request({
35880 method:this.requestMethod,
35881 url: this.dataUrl||this.url,
35882 success: this.handleResponse,
35883 failure: this.handleFailure,
35885 argument: {callback: callback, node: node},
35886 params: this.getParams(node)
35889 // if the load is cancelled, make sure we notify
35890 // the node that we are done
35891 if(typeof callback == "function"){
35897 isLoading : function(){
35898 return this.transId ? true : false;
35901 abort : function(){
35902 if(this.isLoading()){
35903 Roo.Ajax.abort(this.transId);
35908 createNode : function(attr)
35910 // apply baseAttrs, nice idea Corey!
35911 if(this.baseAttrs){
35912 Roo.applyIf(attr, this.baseAttrs);
35914 if(this.applyLoader !== false){
35915 attr.loader = this;
35917 // uiProvider = depreciated..
35919 if(typeof(attr.uiProvider) == 'string'){
35920 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
35921 /** eval:var:attr */ eval(attr.uiProvider);
35923 if(typeof(this.uiProviders['default']) != 'undefined') {
35924 attr.uiProvider = this.uiProviders['default'];
35927 this.fireEvent('create', this, attr);
35929 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
35931 new Roo.tree.TreeNode(attr) :
35932 new Roo.tree.AsyncTreeNode(attr));
35935 processResponse : function(response, node, callback)
35937 var json = response.responseText;
35940 var o = Roo.decode(json);
35942 if (this.root === false && typeof(o.success) != undefined) {
35943 this.root = 'data'; // the default behaviour for list like data..
35946 if (this.root !== false && !o.success) {
35947 // it's a failure condition.
35948 var a = response.argument;
35949 this.fireEvent("loadexception", this, a.node, response);
35950 Roo.log("Load failed - should have a handler really");
35956 if (this.root !== false) {
35960 for(var i = 0, len = o.length; i < len; i++){
35961 var n = this.createNode(o[i]);
35963 node.appendChild(n);
35966 if(typeof callback == "function"){
35967 callback(this, node);
35970 this.handleFailure(response);
35974 handleResponse : function(response){
35975 this.transId = false;
35976 var a = response.argument;
35977 this.processResponse(response, a.node, a.callback);
35978 this.fireEvent("load", this, a.node, response);
35981 handleFailure : function(response)
35983 // should handle failure better..
35984 this.transId = false;
35985 var a = response.argument;
35986 this.fireEvent("loadexception", this, a.node, response);
35987 if(typeof a.callback == "function"){
35988 a.callback(this, a.node);
35993 * Ext JS Library 1.1.1
35994 * Copyright(c) 2006-2007, Ext JS, LLC.
35996 * Originally Released Under LGPL - original licence link has changed is not relivant.
35999 * <script type="text/javascript">
36003 * @class Roo.tree.TreeFilter
36004 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36005 * @param {TreePanel} tree
36006 * @param {Object} config (optional)
36008 Roo.tree.TreeFilter = function(tree, config){
36010 this.filtered = {};
36011 Roo.apply(this, config);
36014 Roo.tree.TreeFilter.prototype = {
36021 * Filter the data by a specific attribute.
36022 * @param {String/RegExp} value Either string that the attribute value
36023 * should start with or a RegExp to test against the attribute
36024 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36025 * @param {TreeNode} startNode (optional) The node to start the filter at.
36027 filter : function(value, attr, startNode){
36028 attr = attr || "text";
36030 if(typeof value == "string"){
36031 var vlen = value.length;
36032 // auto clear empty filter
36033 if(vlen == 0 && this.clearBlank){
36037 value = value.toLowerCase();
36039 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36041 }else if(value.exec){ // regex?
36043 return value.test(n.attributes[attr]);
36046 throw 'Illegal filter type, must be string or regex';
36048 this.filterBy(f, null, startNode);
36052 * Filter by a function. The passed function will be called with each
36053 * node in the tree (or from the startNode). If the function returns true, the node is kept
36054 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36055 * @param {Function} fn The filter function
36056 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36058 filterBy : function(fn, scope, startNode){
36059 startNode = startNode || this.tree.root;
36060 if(this.autoClear){
36063 var af = this.filtered, rv = this.reverse;
36064 var f = function(n){
36065 if(n == startNode){
36071 var m = fn.call(scope || n, n);
36079 startNode.cascade(f);
36082 if(typeof id != "function"){
36084 if(n && n.parentNode){
36085 n.parentNode.removeChild(n);
36093 * Clears the current filter. Note: with the "remove" option
36094 * set a filter cannot be cleared.
36096 clear : function(){
36098 var af = this.filtered;
36100 if(typeof id != "function"){
36107 this.filtered = {};
36112 * Ext JS Library 1.1.1
36113 * Copyright(c) 2006-2007, Ext JS, LLC.
36115 * Originally Released Under LGPL - original licence link has changed is not relivant.
36118 * <script type="text/javascript">
36123 * @class Roo.tree.TreeSorter
36124 * Provides sorting of nodes in a TreePanel
36126 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36127 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36128 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36129 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36130 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36131 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36133 * @param {TreePanel} tree
36134 * @param {Object} config
36136 Roo.tree.TreeSorter = function(tree, config){
36137 Roo.apply(this, config);
36138 tree.on("beforechildrenrendered", this.doSort, this);
36139 tree.on("append", this.updateSort, this);
36140 tree.on("insert", this.updateSort, this);
36142 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36143 var p = this.property || "text";
36144 var sortType = this.sortType;
36145 var fs = this.folderSort;
36146 var cs = this.caseSensitive === true;
36147 var leafAttr = this.leafAttr || 'leaf';
36149 this.sortFn = function(n1, n2){
36151 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36154 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36158 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36159 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36161 return dsc ? +1 : -1;
36163 return dsc ? -1 : +1;
36170 Roo.tree.TreeSorter.prototype = {
36171 doSort : function(node){
36172 node.sort(this.sortFn);
36175 compareNodes : function(n1, n2){
36176 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36179 updateSort : function(tree, node){
36180 if(node.childrenRendered){
36181 this.doSort.defer(1, this, [node]);
36186 * Ext JS Library 1.1.1
36187 * Copyright(c) 2006-2007, Ext JS, LLC.
36189 * Originally Released Under LGPL - original licence link has changed is not relivant.
36192 * <script type="text/javascript">
36195 if(Roo.dd.DropZone){
36197 Roo.tree.TreeDropZone = function(tree, config){
36198 this.allowParentInsert = false;
36199 this.allowContainerDrop = false;
36200 this.appendOnly = false;
36201 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36203 this.lastInsertClass = "x-tree-no-status";
36204 this.dragOverData = {};
36207 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36208 ddGroup : "TreeDD",
36211 expandDelay : 1000,
36213 expandNode : function(node){
36214 if(node.hasChildNodes() && !node.isExpanded()){
36215 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36219 queueExpand : function(node){
36220 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36223 cancelExpand : function(){
36224 if(this.expandProcId){
36225 clearTimeout(this.expandProcId);
36226 this.expandProcId = false;
36230 isValidDropPoint : function(n, pt, dd, e, data){
36231 if(!n || !data){ return false; }
36232 var targetNode = n.node;
36233 var dropNode = data.node;
36234 // default drop rules
36235 if(!(targetNode && targetNode.isTarget && pt)){
36238 if(pt == "append" && targetNode.allowChildren === false){
36241 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36244 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36247 // reuse the object
36248 var overEvent = this.dragOverData;
36249 overEvent.tree = this.tree;
36250 overEvent.target = targetNode;
36251 overEvent.data = data;
36252 overEvent.point = pt;
36253 overEvent.source = dd;
36254 overEvent.rawEvent = e;
36255 overEvent.dropNode = dropNode;
36256 overEvent.cancel = false;
36257 var result = this.tree.fireEvent("nodedragover", overEvent);
36258 return overEvent.cancel === false && result !== false;
36261 getDropPoint : function(e, n, dd)
36265 return tn.allowChildren !== false ? "append" : false; // always append for root
36267 var dragEl = n.ddel;
36268 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36269 var y = Roo.lib.Event.getPageY(e);
36270 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36272 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36273 var noAppend = tn.allowChildren === false;
36274 if(this.appendOnly || tn.parentNode.allowChildren === false){
36275 return noAppend ? false : "append";
36277 var noBelow = false;
36278 if(!this.allowParentInsert){
36279 noBelow = tn.hasChildNodes() && tn.isExpanded();
36281 var q = (b - t) / (noAppend ? 2 : 3);
36282 if(y >= t && y < (t + q)){
36284 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36291 onNodeEnter : function(n, dd, e, data)
36293 this.cancelExpand();
36296 onNodeOver : function(n, dd, e, data)
36299 var pt = this.getDropPoint(e, n, dd);
36302 // auto node expand check
36303 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36304 this.queueExpand(node);
36305 }else if(pt != "append"){
36306 this.cancelExpand();
36309 // set the insert point style on the target node
36310 var returnCls = this.dropNotAllowed;
36311 if(this.isValidDropPoint(n, pt, dd, e, data)){
36316 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36317 cls = "x-tree-drag-insert-above";
36318 }else if(pt == "below"){
36319 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36320 cls = "x-tree-drag-insert-below";
36322 returnCls = "x-tree-drop-ok-append";
36323 cls = "x-tree-drag-append";
36325 if(this.lastInsertClass != cls){
36326 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36327 this.lastInsertClass = cls;
36334 onNodeOut : function(n, dd, e, data){
36336 this.cancelExpand();
36337 this.removeDropIndicators(n);
36340 onNodeDrop : function(n, dd, e, data){
36341 var point = this.getDropPoint(e, n, dd);
36342 var targetNode = n.node;
36343 targetNode.ui.startDrop();
36344 if(!this.isValidDropPoint(n, point, dd, e, data)){
36345 targetNode.ui.endDrop();
36348 // first try to find the drop node
36349 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36352 target: targetNode,
36357 dropNode: dropNode,
36360 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36361 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36362 targetNode.ui.endDrop();
36365 // allow target changing
36366 targetNode = dropEvent.target;
36367 if(point == "append" && !targetNode.isExpanded()){
36368 targetNode.expand(false, null, function(){
36369 this.completeDrop(dropEvent);
36370 }.createDelegate(this));
36372 this.completeDrop(dropEvent);
36377 completeDrop : function(de){
36378 var ns = de.dropNode, p = de.point, t = de.target;
36379 if(!(ns instanceof Array)){
36383 for(var i = 0, len = ns.length; i < len; i++){
36386 t.parentNode.insertBefore(n, t);
36387 }else if(p == "below"){
36388 t.parentNode.insertBefore(n, t.nextSibling);
36394 if(this.tree.hlDrop){
36398 this.tree.fireEvent("nodedrop", de);
36401 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36402 if(this.tree.hlDrop){
36403 dropNode.ui.focus();
36404 dropNode.ui.highlight();
36406 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36409 getTree : function(){
36413 removeDropIndicators : function(n){
36416 Roo.fly(el).removeClass([
36417 "x-tree-drag-insert-above",
36418 "x-tree-drag-insert-below",
36419 "x-tree-drag-append"]);
36420 this.lastInsertClass = "_noclass";
36424 beforeDragDrop : function(target, e, id){
36425 this.cancelExpand();
36429 afterRepair : function(data){
36430 if(data && Roo.enableFx){
36431 data.node.ui.highlight();
36441 * Ext JS Library 1.1.1
36442 * Copyright(c) 2006-2007, Ext JS, LLC.
36444 * Originally Released Under LGPL - original licence link has changed is not relivant.
36447 * <script type="text/javascript">
36451 if(Roo.dd.DragZone){
36452 Roo.tree.TreeDragZone = function(tree, config){
36453 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36457 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36458 ddGroup : "TreeDD",
36460 onBeforeDrag : function(data, e){
36462 return n && n.draggable && !n.disabled;
36466 onInitDrag : function(e){
36467 var data = this.dragData;
36468 this.tree.getSelectionModel().select(data.node);
36469 this.proxy.update("");
36470 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36471 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36474 getRepairXY : function(e, data){
36475 return data.node.ui.getDDRepairXY();
36478 onEndDrag : function(data, e){
36479 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36484 onValidDrop : function(dd, e, id){
36485 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36489 beforeInvalidDrop : function(e, id){
36490 // this scrolls the original position back into view
36491 var sm = this.tree.getSelectionModel();
36492 sm.clearSelections();
36493 sm.select(this.dragData.node);
36498 * Ext JS Library 1.1.1
36499 * Copyright(c) 2006-2007, Ext JS, LLC.
36501 * Originally Released Under LGPL - original licence link has changed is not relivant.
36504 * <script type="text/javascript">
36507 * @class Roo.tree.TreeEditor
36508 * @extends Roo.Editor
36509 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36510 * as the editor field.
36512 * @param {Object} config (used to be the tree panel.)
36513 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36515 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36516 * @cfg {Roo.form.TextField|Object} field The field configuration
36520 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36523 if (oldconfig) { // old style..
36524 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36527 tree = config.tree;
36528 config.field = config.field || {};
36529 config.field.xtype = 'TextField';
36530 field = Roo.factory(config.field, Roo.form);
36532 config = config || {};
36537 * @event beforenodeedit
36538 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36539 * false from the handler of this event.
36540 * @param {Editor} this
36541 * @param {Roo.tree.Node} node
36543 "beforenodeedit" : true
36547 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36551 tree.on('beforeclick', this.beforeNodeClick, this);
36552 tree.getTreeEl().on('mousedown', this.hide, this);
36553 this.on('complete', this.updateNode, this);
36554 this.on('beforestartedit', this.fitToTree, this);
36555 this.on('startedit', this.bindScroll, this, {delay:10});
36556 this.on('specialkey', this.onSpecialKey, this);
36559 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36561 * @cfg {String} alignment
36562 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36568 * @cfg {Boolean} hideEl
36569 * True to hide the bound element while the editor is displayed (defaults to false)
36573 * @cfg {String} cls
36574 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36576 cls: "x-small-editor x-tree-editor",
36578 * @cfg {Boolean} shim
36579 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36585 * @cfg {Number} maxWidth
36586 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36587 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36588 * scroll and client offsets into account prior to each edit.
36595 fitToTree : function(ed, el){
36596 var td = this.tree.getTreeEl().dom, nd = el.dom;
36597 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36598 td.scrollLeft = nd.offsetLeft;
36602 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36603 this.setSize(w, '');
36605 return this.fireEvent('beforenodeedit', this, this.editNode);
36610 triggerEdit : function(node){
36611 this.completeEdit();
36612 this.editNode = node;
36613 this.startEdit(node.ui.textNode, node.text);
36617 bindScroll : function(){
36618 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36622 beforeNodeClick : function(node, e){
36623 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36624 this.lastClick = new Date();
36625 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36627 this.triggerEdit(node);
36634 updateNode : function(ed, value){
36635 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36636 this.editNode.setText(value);
36640 onHide : function(){
36641 Roo.tree.TreeEditor.superclass.onHide.call(this);
36643 this.editNode.ui.focus();
36648 onSpecialKey : function(field, e){
36649 var k = e.getKey();
36653 }else if(k == e.ENTER && !e.hasModifier()){
36655 this.completeEdit();
36658 });//<Script type="text/javascript">
36661 * Ext JS Library 1.1.1
36662 * Copyright(c) 2006-2007, Ext JS, LLC.
36664 * Originally Released Under LGPL - original licence link has changed is not relivant.
36667 * <script type="text/javascript">
36671 * Not documented??? - probably should be...
36674 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36675 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36677 renderElements : function(n, a, targetNode, bulkRender){
36678 //consel.log("renderElements?");
36679 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36681 var t = n.getOwnerTree();
36682 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36684 var cols = t.columns;
36685 var bw = t.borderWidth;
36687 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36688 var cb = typeof a.checked == "boolean";
36689 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36690 var colcls = 'x-t-' + tid + '-c0';
36692 '<li class="x-tree-node">',
36695 '<div class="x-tree-node-el ', a.cls,'">',
36697 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36700 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36701 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36702 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36703 (a.icon ? ' x-tree-node-inline-icon' : ''),
36704 (a.iconCls ? ' '+a.iconCls : ''),
36705 '" unselectable="on" />',
36706 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36707 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36709 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36710 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36711 '<span unselectable="on" qtip="' + tx + '">',
36715 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36716 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36718 for(var i = 1, len = cols.length; i < len; i++){
36720 colcls = 'x-t-' + tid + '-c' +i;
36721 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36722 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36723 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36729 '<div class="x-clear"></div></div>',
36730 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36733 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36734 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36735 n.nextSibling.ui.getEl(), buf.join(""));
36737 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36739 var el = this.wrap.firstChild;
36741 this.elNode = el.firstChild;
36742 this.ranchor = el.childNodes[1];
36743 this.ctNode = this.wrap.childNodes[1];
36744 var cs = el.firstChild.childNodes;
36745 this.indentNode = cs[0];
36746 this.ecNode = cs[1];
36747 this.iconNode = cs[2];
36750 this.checkbox = cs[3];
36753 this.anchor = cs[index];
36755 this.textNode = cs[index].firstChild;
36757 //el.on("click", this.onClick, this);
36758 //el.on("dblclick", this.onDblClick, this);
36761 // console.log(this);
36763 initEvents : function(){
36764 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36767 var a = this.ranchor;
36769 var el = Roo.get(a);
36771 if(Roo.isOpera){ // opera render bug ignores the CSS
36772 el.setStyle("text-decoration", "none");
36775 el.on("click", this.onClick, this);
36776 el.on("dblclick", this.onDblClick, this);
36777 el.on("contextmenu", this.onContextMenu, this);
36781 /*onSelectedChange : function(state){
36784 this.addClass("x-tree-selected");
36787 this.removeClass("x-tree-selected");
36790 addClass : function(cls){
36792 Roo.fly(this.elRow).addClass(cls);
36798 removeClass : function(cls){
36800 Roo.fly(this.elRow).removeClass(cls);
36806 });//<Script type="text/javascript">
36810 * Ext JS Library 1.1.1
36811 * Copyright(c) 2006-2007, Ext JS, LLC.
36813 * Originally Released Under LGPL - original licence link has changed is not relivant.
36816 * <script type="text/javascript">
36821 * @class Roo.tree.ColumnTree
36822 * @extends Roo.data.TreePanel
36823 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36824 * @cfg {int} borderWidth compined right/left border allowance
36826 * @param {String/HTMLElement/Element} el The container element
36827 * @param {Object} config
36829 Roo.tree.ColumnTree = function(el, config)
36831 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36835 * Fire this event on a container when it resizes
36836 * @param {int} w Width
36837 * @param {int} h Height
36841 this.on('resize', this.onResize, this);
36844 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
36848 borderWidth: Roo.isBorderBox ? 0 : 2,
36851 render : function(){
36852 // add the header.....
36854 Roo.tree.ColumnTree.superclass.render.apply(this);
36856 this.el.addClass('x-column-tree');
36858 this.headers = this.el.createChild(
36859 {cls:'x-tree-headers'},this.innerCt.dom);
36861 var cols = this.columns, c;
36862 var totalWidth = 0;
36864 var len = cols.length;
36865 for(var i = 0; i < len; i++){
36867 totalWidth += c.width;
36868 this.headEls.push(this.headers.createChild({
36869 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
36871 cls:'x-tree-hd-text',
36874 style:'width:'+(c.width-this.borderWidth)+'px;'
36877 this.headers.createChild({cls:'x-clear'});
36878 // prevent floats from wrapping when clipped
36879 this.headers.setWidth(totalWidth);
36880 //this.innerCt.setWidth(totalWidth);
36881 this.innerCt.setStyle({ overflow: 'auto' });
36882 this.onResize(this.width, this.height);
36886 onResize : function(w,h)
36891 this.innerCt.setWidth(this.width);
36892 this.innerCt.setHeight(this.height-20);
36895 var cols = this.columns, c;
36896 var totalWidth = 0;
36898 var len = cols.length;
36899 for(var i = 0; i < len; i++){
36901 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
36902 // it's the expander..
36903 expEl = this.headEls[i];
36906 totalWidth += c.width;
36910 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
36912 this.headers.setWidth(w-20);
36921 * Ext JS Library 1.1.1
36922 * Copyright(c) 2006-2007, Ext JS, LLC.
36924 * Originally Released Under LGPL - original licence link has changed is not relivant.
36927 * <script type="text/javascript">
36931 * @class Roo.menu.Menu
36932 * @extends Roo.util.Observable
36933 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
36934 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
36936 * Creates a new Menu
36937 * @param {Object} config Configuration options
36939 Roo.menu.Menu = function(config){
36940 Roo.apply(this, config);
36941 this.id = this.id || Roo.id();
36944 * @event beforeshow
36945 * Fires before this menu is displayed
36946 * @param {Roo.menu.Menu} this
36950 * @event beforehide
36951 * Fires before this menu is hidden
36952 * @param {Roo.menu.Menu} this
36957 * Fires after this menu is displayed
36958 * @param {Roo.menu.Menu} this
36963 * Fires after this menu is hidden
36964 * @param {Roo.menu.Menu} this
36969 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
36970 * @param {Roo.menu.Menu} this
36971 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36972 * @param {Roo.EventObject} e
36977 * Fires when the mouse is hovering over this menu
36978 * @param {Roo.menu.Menu} this
36979 * @param {Roo.EventObject} e
36980 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36985 * Fires when the mouse exits this menu
36986 * @param {Roo.menu.Menu} this
36987 * @param {Roo.EventObject} e
36988 * @param {Roo.menu.Item} menuItem The menu item that was clicked
36993 * Fires when a menu item contained in this menu is clicked
36994 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
36995 * @param {Roo.EventObject} e
36999 if (this.registerMenu) {
37000 Roo.menu.MenuMgr.register(this);
37003 var mis = this.items;
37004 this.items = new Roo.util.MixedCollection();
37006 this.add.apply(this, mis);
37010 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37012 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37016 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37017 * for bottom-right shadow (defaults to "sides")
37021 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37022 * this menu (defaults to "tl-tr?")
37024 subMenuAlign : "tl-tr?",
37026 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37027 * relative to its element of origin (defaults to "tl-bl?")
37029 defaultAlign : "tl-bl?",
37031 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37033 allowOtherMenus : false,
37035 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37037 registerMenu : true,
37042 render : function(){
37046 var el = this.el = new Roo.Layer({
37048 shadow:this.shadow,
37050 parentEl: this.parentEl || document.body,
37054 this.keyNav = new Roo.menu.MenuNav(this);
37057 el.addClass("x-menu-plain");
37060 el.addClass(this.cls);
37062 // generic focus element
37063 this.focusEl = el.createChild({
37064 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37066 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37067 //disabling touch- as it's causing issues ..
37068 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37069 ul.on('click' , this.onClick, this);
37072 ul.on("mouseover", this.onMouseOver, this);
37073 ul.on("mouseout", this.onMouseOut, this);
37074 this.items.each(function(item){
37079 var li = document.createElement("li");
37080 li.className = "x-menu-list-item";
37081 ul.dom.appendChild(li);
37082 item.render(li, this);
37089 autoWidth : function(){
37090 var el = this.el, ul = this.ul;
37094 var w = this.width;
37097 }else if(Roo.isIE){
37098 el.setWidth(this.minWidth);
37099 var t = el.dom.offsetWidth; // force recalc
37100 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37105 delayAutoWidth : function(){
37108 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37110 this.awTask.delay(20);
37115 findTargetItem : function(e){
37116 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37117 if(t && t.menuItemId){
37118 return this.items.get(t.menuItemId);
37123 onClick : function(e){
37124 Roo.log("menu.onClick");
37125 var t = this.findTargetItem(e);
37130 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37131 if(t == this.activeItem && t.shouldDeactivate(e)){
37132 this.activeItem.deactivate();
37133 delete this.activeItem;
37137 this.setActiveItem(t, true);
37145 this.fireEvent("click", this, t, e);
37149 setActiveItem : function(item, autoExpand){
37150 if(item != this.activeItem){
37151 if(this.activeItem){
37152 this.activeItem.deactivate();
37154 this.activeItem = item;
37155 item.activate(autoExpand);
37156 }else if(autoExpand){
37162 tryActivate : function(start, step){
37163 var items = this.items;
37164 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37165 var item = items.get(i);
37166 if(!item.disabled && item.canActivate){
37167 this.setActiveItem(item, false);
37175 onMouseOver : function(e){
37177 if(t = this.findTargetItem(e)){
37178 if(t.canActivate && !t.disabled){
37179 this.setActiveItem(t, true);
37182 this.fireEvent("mouseover", this, e, t);
37186 onMouseOut : function(e){
37188 if(t = this.findTargetItem(e)){
37189 if(t == this.activeItem && t.shouldDeactivate(e)){
37190 this.activeItem.deactivate();
37191 delete this.activeItem;
37194 this.fireEvent("mouseout", this, e, t);
37198 * Read-only. Returns true if the menu is currently displayed, else false.
37201 isVisible : function(){
37202 return this.el && !this.hidden;
37206 * Displays this menu relative to another element
37207 * @param {String/HTMLElement/Roo.Element} element The element to align to
37208 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37209 * the element (defaults to this.defaultAlign)
37210 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37212 show : function(el, pos, parentMenu){
37213 this.parentMenu = parentMenu;
37217 this.fireEvent("beforeshow", this);
37218 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37222 * Displays this menu at a specific xy position
37223 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37224 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37226 showAt : function(xy, parentMenu, /* private: */_e){
37227 this.parentMenu = parentMenu;
37232 this.fireEvent("beforeshow", this);
37233 xy = this.el.adjustForConstraints(xy);
37237 this.hidden = false;
37239 this.fireEvent("show", this);
37242 focus : function(){
37244 this.doFocus.defer(50, this);
37248 doFocus : function(){
37250 this.focusEl.focus();
37255 * Hides this menu and optionally all parent menus
37256 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37258 hide : function(deep){
37259 if(this.el && this.isVisible()){
37260 this.fireEvent("beforehide", this);
37261 if(this.activeItem){
37262 this.activeItem.deactivate();
37263 this.activeItem = null;
37266 this.hidden = true;
37267 this.fireEvent("hide", this);
37269 if(deep === true && this.parentMenu){
37270 this.parentMenu.hide(true);
37275 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37276 * Any of the following are valid:
37278 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37279 * <li>An HTMLElement object which will be converted to a menu item</li>
37280 * <li>A menu item config object that will be created as a new menu item</li>
37281 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37282 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37287 var menu = new Roo.menu.Menu();
37289 // Create a menu item to add by reference
37290 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37292 // Add a bunch of items at once using different methods.
37293 // Only the last item added will be returned.
37294 var item = menu.add(
37295 menuItem, // add existing item by ref
37296 'Dynamic Item', // new TextItem
37297 '-', // new separator
37298 { text: 'Config Item' } // new item by config
37301 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37302 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37305 var a = arguments, l = a.length, item;
37306 for(var i = 0; i < l; i++){
37308 if ((typeof(el) == "object") && el.xtype && el.xns) {
37309 el = Roo.factory(el, Roo.menu);
37312 if(el.render){ // some kind of Item
37313 item = this.addItem(el);
37314 }else if(typeof el == "string"){ // string
37315 if(el == "separator" || el == "-"){
37316 item = this.addSeparator();
37318 item = this.addText(el);
37320 }else if(el.tagName || el.el){ // element
37321 item = this.addElement(el);
37322 }else if(typeof el == "object"){ // must be menu item config?
37323 item = this.addMenuItem(el);
37330 * Returns this menu's underlying {@link Roo.Element} object
37331 * @return {Roo.Element} The element
37333 getEl : function(){
37341 * Adds a separator bar to the menu
37342 * @return {Roo.menu.Item} The menu item that was added
37344 addSeparator : function(){
37345 return this.addItem(new Roo.menu.Separator());
37349 * Adds an {@link Roo.Element} object to the menu
37350 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37351 * @return {Roo.menu.Item} The menu item that was added
37353 addElement : function(el){
37354 return this.addItem(new Roo.menu.BaseItem(el));
37358 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37359 * @param {Roo.menu.Item} item The menu item to add
37360 * @return {Roo.menu.Item} The menu item that was added
37362 addItem : function(item){
37363 this.items.add(item);
37365 var li = document.createElement("li");
37366 li.className = "x-menu-list-item";
37367 this.ul.dom.appendChild(li);
37368 item.render(li, this);
37369 this.delayAutoWidth();
37375 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37376 * @param {Object} config A MenuItem config object
37377 * @return {Roo.menu.Item} The menu item that was added
37379 addMenuItem : function(config){
37380 if(!(config instanceof Roo.menu.Item)){
37381 if(typeof config.checked == "boolean"){ // must be check menu item config?
37382 config = new Roo.menu.CheckItem(config);
37384 config = new Roo.menu.Item(config);
37387 return this.addItem(config);
37391 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37392 * @param {String} text The text to display in the menu item
37393 * @return {Roo.menu.Item} The menu item that was added
37395 addText : function(text){
37396 return this.addItem(new Roo.menu.TextItem({ text : text }));
37400 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37401 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37402 * @param {Roo.menu.Item} item The menu item to add
37403 * @return {Roo.menu.Item} The menu item that was added
37405 insert : function(index, item){
37406 this.items.insert(index, item);
37408 var li = document.createElement("li");
37409 li.className = "x-menu-list-item";
37410 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37411 item.render(li, this);
37412 this.delayAutoWidth();
37418 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37419 * @param {Roo.menu.Item} item The menu item to remove
37421 remove : function(item){
37422 this.items.removeKey(item.id);
37427 * Removes and destroys all items in the menu
37429 removeAll : function(){
37431 while(f = this.items.first()){
37437 // MenuNav is a private utility class used internally by the Menu
37438 Roo.menu.MenuNav = function(menu){
37439 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37440 this.scope = this.menu = menu;
37443 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37444 doRelay : function(e, h){
37445 var k = e.getKey();
37446 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37447 this.menu.tryActivate(0, 1);
37450 return h.call(this.scope || this, e, this.menu);
37453 up : function(e, m){
37454 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37455 m.tryActivate(m.items.length-1, -1);
37459 down : function(e, m){
37460 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37461 m.tryActivate(0, 1);
37465 right : function(e, m){
37467 m.activeItem.expandMenu(true);
37471 left : function(e, m){
37473 if(m.parentMenu && m.parentMenu.activeItem){
37474 m.parentMenu.activeItem.activate();
37478 enter : function(e, m){
37480 e.stopPropagation();
37481 m.activeItem.onClick(e);
37482 m.fireEvent("click", this, m.activeItem);
37488 * Ext JS Library 1.1.1
37489 * Copyright(c) 2006-2007, Ext JS, LLC.
37491 * Originally Released Under LGPL - original licence link has changed is not relivant.
37494 * <script type="text/javascript">
37498 * @class Roo.menu.MenuMgr
37499 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37502 Roo.menu.MenuMgr = function(){
37503 var menus, active, groups = {}, attached = false, lastShow = new Date();
37505 // private - called when first menu is created
37508 active = new Roo.util.MixedCollection();
37509 Roo.get(document).addKeyListener(27, function(){
37510 if(active.length > 0){
37517 function hideAll(){
37518 if(active && active.length > 0){
37519 var c = active.clone();
37520 c.each(function(m){
37527 function onHide(m){
37529 if(active.length < 1){
37530 Roo.get(document).un("mousedown", onMouseDown);
37536 function onShow(m){
37537 var last = active.last();
37538 lastShow = new Date();
37541 Roo.get(document).on("mousedown", onMouseDown);
37545 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37546 m.parentMenu.activeChild = m;
37547 }else if(last && last.isVisible()){
37548 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37553 function onBeforeHide(m){
37555 m.activeChild.hide();
37557 if(m.autoHideTimer){
37558 clearTimeout(m.autoHideTimer);
37559 delete m.autoHideTimer;
37564 function onBeforeShow(m){
37565 var pm = m.parentMenu;
37566 if(!pm && !m.allowOtherMenus){
37568 }else if(pm && pm.activeChild && active != m){
37569 pm.activeChild.hide();
37574 function onMouseDown(e){
37575 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37581 function onBeforeCheck(mi, state){
37583 var g = groups[mi.group];
37584 for(var i = 0, l = g.length; i < l; i++){
37586 g[i].setChecked(false);
37595 * Hides all menus that are currently visible
37597 hideAll : function(){
37602 register : function(menu){
37606 menus[menu.id] = menu;
37607 menu.on("beforehide", onBeforeHide);
37608 menu.on("hide", onHide);
37609 menu.on("beforeshow", onBeforeShow);
37610 menu.on("show", onShow);
37611 var g = menu.group;
37612 if(g && menu.events["checkchange"]){
37616 groups[g].push(menu);
37617 menu.on("checkchange", onCheck);
37622 * Returns a {@link Roo.menu.Menu} object
37623 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37624 * be used to generate and return a new Menu instance.
37626 get : function(menu){
37627 if(typeof menu == "string"){ // menu id
37628 return menus[menu];
37629 }else if(menu.events){ // menu instance
37631 }else if(typeof menu.length == 'number'){ // array of menu items?
37632 return new Roo.menu.Menu({items:menu});
37633 }else{ // otherwise, must be a config
37634 return new Roo.menu.Menu(menu);
37639 unregister : function(menu){
37640 delete menus[menu.id];
37641 menu.un("beforehide", onBeforeHide);
37642 menu.un("hide", onHide);
37643 menu.un("beforeshow", onBeforeShow);
37644 menu.un("show", onShow);
37645 var g = menu.group;
37646 if(g && menu.events["checkchange"]){
37647 groups[g].remove(menu);
37648 menu.un("checkchange", onCheck);
37653 registerCheckable : function(menuItem){
37654 var g = menuItem.group;
37659 groups[g].push(menuItem);
37660 menuItem.on("beforecheckchange", onBeforeCheck);
37665 unregisterCheckable : function(menuItem){
37666 var g = menuItem.group;
37668 groups[g].remove(menuItem);
37669 menuItem.un("beforecheckchange", onBeforeCheck);
37675 * Ext JS Library 1.1.1
37676 * Copyright(c) 2006-2007, Ext JS, LLC.
37678 * Originally Released Under LGPL - original licence link has changed is not relivant.
37681 * <script type="text/javascript">
37686 * @class Roo.menu.BaseItem
37687 * @extends Roo.Component
37688 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37689 * management and base configuration options shared by all menu components.
37691 * Creates a new BaseItem
37692 * @param {Object} config Configuration options
37694 Roo.menu.BaseItem = function(config){
37695 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37700 * Fires when this item is clicked
37701 * @param {Roo.menu.BaseItem} this
37702 * @param {Roo.EventObject} e
37707 * Fires when this item is activated
37708 * @param {Roo.menu.BaseItem} this
37712 * @event deactivate
37713 * Fires when this item is deactivated
37714 * @param {Roo.menu.BaseItem} this
37720 this.on("click", this.handler, this.scope, true);
37724 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37726 * @cfg {Function} handler
37727 * A function that will handle the click event of this menu item (defaults to undefined)
37730 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37732 canActivate : false,
37735 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37740 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37742 activeClass : "x-menu-item-active",
37744 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37746 hideOnClick : true,
37748 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37753 ctype: "Roo.menu.BaseItem",
37756 actionMode : "container",
37759 render : function(container, parentMenu){
37760 this.parentMenu = parentMenu;
37761 Roo.menu.BaseItem.superclass.render.call(this, container);
37762 this.container.menuItemId = this.id;
37766 onRender : function(container, position){
37767 this.el = Roo.get(this.el);
37768 container.dom.appendChild(this.el.dom);
37772 onClick : function(e){
37773 if(!this.disabled && this.fireEvent("click", this, e) !== false
37774 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37775 this.handleClick(e);
37782 activate : function(){
37786 var li = this.container;
37787 li.addClass(this.activeClass);
37788 this.region = li.getRegion().adjust(2, 2, -2, -2);
37789 this.fireEvent("activate", this);
37794 deactivate : function(){
37795 this.container.removeClass(this.activeClass);
37796 this.fireEvent("deactivate", this);
37800 shouldDeactivate : function(e){
37801 return !this.region || !this.region.contains(e.getPoint());
37805 handleClick : function(e){
37806 if(this.hideOnClick){
37807 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37812 expandMenu : function(autoActivate){
37817 hideMenu : function(){
37822 * Ext JS Library 1.1.1
37823 * Copyright(c) 2006-2007, Ext JS, LLC.
37825 * Originally Released Under LGPL - original licence link has changed is not relivant.
37828 * <script type="text/javascript">
37832 * @class Roo.menu.Adapter
37833 * @extends Roo.menu.BaseItem
37834 * 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.
37835 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37837 * Creates a new Adapter
37838 * @param {Object} config Configuration options
37840 Roo.menu.Adapter = function(component, config){
37841 Roo.menu.Adapter.superclass.constructor.call(this, config);
37842 this.component = component;
37844 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37846 canActivate : true,
37849 onRender : function(container, position){
37850 this.component.render(container);
37851 this.el = this.component.getEl();
37855 activate : function(){
37859 this.component.focus();
37860 this.fireEvent("activate", this);
37865 deactivate : function(){
37866 this.fireEvent("deactivate", this);
37870 disable : function(){
37871 this.component.disable();
37872 Roo.menu.Adapter.superclass.disable.call(this);
37876 enable : function(){
37877 this.component.enable();
37878 Roo.menu.Adapter.superclass.enable.call(this);
37882 * Ext JS Library 1.1.1
37883 * Copyright(c) 2006-2007, Ext JS, LLC.
37885 * Originally Released Under LGPL - original licence link has changed is not relivant.
37888 * <script type="text/javascript">
37892 * @class Roo.menu.TextItem
37893 * @extends Roo.menu.BaseItem
37894 * Adds a static text string to a menu, usually used as either a heading or group separator.
37895 * Note: old style constructor with text is still supported.
37898 * Creates a new TextItem
37899 * @param {Object} cfg Configuration
37901 Roo.menu.TextItem = function(cfg){
37902 if (typeof(cfg) == 'string') {
37905 Roo.apply(this,cfg);
37908 Roo.menu.TextItem.superclass.constructor.call(this);
37911 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
37913 * @cfg {Boolean} text Text to show on item.
37918 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
37920 hideOnClick : false,
37922 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
37924 itemCls : "x-menu-text",
37927 onRender : function(){
37928 var s = document.createElement("span");
37929 s.className = this.itemCls;
37930 s.innerHTML = this.text;
37932 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
37936 * Ext JS Library 1.1.1
37937 * Copyright(c) 2006-2007, Ext JS, LLC.
37939 * Originally Released Under LGPL - original licence link has changed is not relivant.
37942 * <script type="text/javascript">
37946 * @class Roo.menu.Separator
37947 * @extends Roo.menu.BaseItem
37948 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
37949 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
37951 * @param {Object} config Configuration options
37953 Roo.menu.Separator = function(config){
37954 Roo.menu.Separator.superclass.constructor.call(this, config);
37957 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
37959 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
37961 itemCls : "x-menu-sep",
37963 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
37965 hideOnClick : false,
37968 onRender : function(li){
37969 var s = document.createElement("span");
37970 s.className = this.itemCls;
37971 s.innerHTML = " ";
37973 li.addClass("x-menu-sep-li");
37974 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
37978 * Ext JS Library 1.1.1
37979 * Copyright(c) 2006-2007, Ext JS, LLC.
37981 * Originally Released Under LGPL - original licence link has changed is not relivant.
37984 * <script type="text/javascript">
37987 * @class Roo.menu.Item
37988 * @extends Roo.menu.BaseItem
37989 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
37990 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
37991 * activation and click handling.
37993 * Creates a new Item
37994 * @param {Object} config Configuration options
37996 Roo.menu.Item = function(config){
37997 Roo.menu.Item.superclass.constructor.call(this, config);
37999 this.menu = Roo.menu.MenuMgr.get(this.menu);
38002 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38005 * @cfg {String} text
38006 * The text to show on the menu item.
38010 * @cfg {String} HTML to render in menu
38011 * The text to show on the menu item (HTML version).
38015 * @cfg {String} icon
38016 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38020 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38022 itemCls : "x-menu-item",
38024 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38026 canActivate : true,
38028 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38031 // doc'd in BaseItem
38035 ctype: "Roo.menu.Item",
38038 onRender : function(container, position){
38039 var el = document.createElement("a");
38040 el.hideFocus = true;
38041 el.unselectable = "on";
38042 el.href = this.href || "#";
38043 if(this.hrefTarget){
38044 el.target = this.hrefTarget;
38046 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38048 var html = this.html.length ? this.html : String.format('{0}',this.text);
38050 el.innerHTML = String.format(
38051 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38052 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38054 Roo.menu.Item.superclass.onRender.call(this, container, position);
38058 * Sets the text to display in this menu item
38059 * @param {String} text The text to display
38060 * @param {Boolean} isHTML true to indicate text is pure html.
38062 setText : function(text, isHTML){
38070 var html = this.html.length ? this.html : String.format('{0}',this.text);
38072 this.el.update(String.format(
38073 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38074 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38075 this.parentMenu.autoWidth();
38080 handleClick : function(e){
38081 if(!this.href){ // if no link defined, stop the event automatically
38084 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38088 activate : function(autoExpand){
38089 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38099 shouldDeactivate : function(e){
38100 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38101 if(this.menu && this.menu.isVisible()){
38102 return !this.menu.getEl().getRegion().contains(e.getPoint());
38110 deactivate : function(){
38111 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38116 expandMenu : function(autoActivate){
38117 if(!this.disabled && this.menu){
38118 clearTimeout(this.hideTimer);
38119 delete this.hideTimer;
38120 if(!this.menu.isVisible() && !this.showTimer){
38121 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38122 }else if (this.menu.isVisible() && autoActivate){
38123 this.menu.tryActivate(0, 1);
38129 deferExpand : function(autoActivate){
38130 delete this.showTimer;
38131 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38133 this.menu.tryActivate(0, 1);
38138 hideMenu : function(){
38139 clearTimeout(this.showTimer);
38140 delete this.showTimer;
38141 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38142 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38147 deferHide : function(){
38148 delete this.hideTimer;
38153 * Ext JS Library 1.1.1
38154 * Copyright(c) 2006-2007, Ext JS, LLC.
38156 * Originally Released Under LGPL - original licence link has changed is not relivant.
38159 * <script type="text/javascript">
38163 * @class Roo.menu.CheckItem
38164 * @extends Roo.menu.Item
38165 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38167 * Creates a new CheckItem
38168 * @param {Object} config Configuration options
38170 Roo.menu.CheckItem = function(config){
38171 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38174 * @event beforecheckchange
38175 * Fires before the checked value is set, providing an opportunity to cancel if needed
38176 * @param {Roo.menu.CheckItem} this
38177 * @param {Boolean} checked The new checked value that will be set
38179 "beforecheckchange" : true,
38181 * @event checkchange
38182 * Fires after the checked value has been set
38183 * @param {Roo.menu.CheckItem} this
38184 * @param {Boolean} checked The checked value that was set
38186 "checkchange" : true
38188 if(this.checkHandler){
38189 this.on('checkchange', this.checkHandler, this.scope);
38192 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38194 * @cfg {String} group
38195 * All check items with the same group name will automatically be grouped into a single-select
38196 * radio button group (defaults to '')
38199 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38201 itemCls : "x-menu-item x-menu-check-item",
38203 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38205 groupClass : "x-menu-group-item",
38208 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38209 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38210 * initialized with checked = true will be rendered as checked.
38215 ctype: "Roo.menu.CheckItem",
38218 onRender : function(c){
38219 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38221 this.el.addClass(this.groupClass);
38223 Roo.menu.MenuMgr.registerCheckable(this);
38225 this.checked = false;
38226 this.setChecked(true, true);
38231 destroy : function(){
38233 Roo.menu.MenuMgr.unregisterCheckable(this);
38235 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38239 * Set the checked state of this item
38240 * @param {Boolean} checked The new checked value
38241 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38243 setChecked : function(state, suppressEvent){
38244 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38245 if(this.container){
38246 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38248 this.checked = state;
38249 if(suppressEvent !== true){
38250 this.fireEvent("checkchange", this, state);
38256 handleClick : function(e){
38257 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38258 this.setChecked(!this.checked);
38260 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38264 * Ext JS Library 1.1.1
38265 * Copyright(c) 2006-2007, Ext JS, LLC.
38267 * Originally Released Under LGPL - original licence link has changed is not relivant.
38270 * <script type="text/javascript">
38274 * @class Roo.menu.DateItem
38275 * @extends Roo.menu.Adapter
38276 * A menu item that wraps the {@link Roo.DatPicker} component.
38278 * Creates a new DateItem
38279 * @param {Object} config Configuration options
38281 Roo.menu.DateItem = function(config){
38282 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38283 /** The Roo.DatePicker object @type Roo.DatePicker */
38284 this.picker = this.component;
38285 this.addEvents({select: true});
38287 this.picker.on("render", function(picker){
38288 picker.getEl().swallowEvent("click");
38289 picker.container.addClass("x-menu-date-item");
38292 this.picker.on("select", this.onSelect, this);
38295 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38297 onSelect : function(picker, date){
38298 this.fireEvent("select", this, date, picker);
38299 Roo.menu.DateItem.superclass.handleClick.call(this);
38303 * Ext JS Library 1.1.1
38304 * Copyright(c) 2006-2007, Ext JS, LLC.
38306 * Originally Released Under LGPL - original licence link has changed is not relivant.
38309 * <script type="text/javascript">
38313 * @class Roo.menu.ColorItem
38314 * @extends Roo.menu.Adapter
38315 * A menu item that wraps the {@link Roo.ColorPalette} component.
38317 * Creates a new ColorItem
38318 * @param {Object} config Configuration options
38320 Roo.menu.ColorItem = function(config){
38321 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38322 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38323 this.palette = this.component;
38324 this.relayEvents(this.palette, ["select"]);
38325 if(this.selectHandler){
38326 this.on('select', this.selectHandler, this.scope);
38329 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38331 * Ext JS Library 1.1.1
38332 * Copyright(c) 2006-2007, Ext JS, LLC.
38334 * Originally Released Under LGPL - original licence link has changed is not relivant.
38337 * <script type="text/javascript">
38342 * @class Roo.menu.DateMenu
38343 * @extends Roo.menu.Menu
38344 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38346 * Creates a new DateMenu
38347 * @param {Object} config Configuration options
38349 Roo.menu.DateMenu = function(config){
38350 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38352 var di = new Roo.menu.DateItem(config);
38355 * The {@link Roo.DatePicker} instance for this DateMenu
38358 this.picker = di.picker;
38361 * @param {DatePicker} picker
38362 * @param {Date} date
38364 this.relayEvents(di, ["select"]);
38365 this.on('beforeshow', function(){
38367 this.picker.hideMonthPicker(false);
38371 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38375 * Ext JS Library 1.1.1
38376 * Copyright(c) 2006-2007, Ext JS, LLC.
38378 * Originally Released Under LGPL - original licence link has changed is not relivant.
38381 * <script type="text/javascript">
38386 * @class Roo.menu.ColorMenu
38387 * @extends Roo.menu.Menu
38388 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38390 * Creates a new ColorMenu
38391 * @param {Object} config Configuration options
38393 Roo.menu.ColorMenu = function(config){
38394 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38396 var ci = new Roo.menu.ColorItem(config);
38399 * The {@link Roo.ColorPalette} instance for this ColorMenu
38400 * @type ColorPalette
38402 this.palette = ci.palette;
38405 * @param {ColorPalette} palette
38406 * @param {String} color
38408 this.relayEvents(ci, ["select"]);
38410 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38412 * Ext JS Library 1.1.1
38413 * Copyright(c) 2006-2007, Ext JS, LLC.
38415 * Originally Released Under LGPL - original licence link has changed is not relivant.
38418 * <script type="text/javascript">
38422 * @class Roo.form.Field
38423 * @extends Roo.BoxComponent
38424 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38426 * Creates a new Field
38427 * @param {Object} config Configuration options
38429 Roo.form.Field = function(config){
38430 Roo.form.Field.superclass.constructor.call(this, config);
38433 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38435 * @cfg {String} fieldLabel Label to use when rendering a form.
38438 * @cfg {String} qtip Mouse over tip
38442 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38444 invalidClass : "x-form-invalid",
38446 * @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")
38448 invalidText : "The value in this field is invalid",
38450 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38452 focusClass : "x-form-focus",
38454 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38455 automatic validation (defaults to "keyup").
38457 validationEvent : "keyup",
38459 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38461 validateOnBlur : true,
38463 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38465 validationDelay : 250,
38467 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38468 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38470 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38472 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38474 fieldClass : "x-form-field",
38476 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38479 ----------- ----------------------------------------------------------------------
38480 qtip Display a quick tip when the user hovers over the field
38481 title Display a default browser title attribute popup
38482 under Add a block div beneath the field containing the error text
38483 side Add an error icon to the right of the field with a popup on hover
38484 [element id] Add the error text directly to the innerHTML of the specified element
38487 msgTarget : 'qtip',
38489 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38494 * @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.
38499 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38504 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38506 inputType : undefined,
38509 * @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).
38511 tabIndex : undefined,
38514 isFormField : true,
38519 * @property {Roo.Element} fieldEl
38520 * Element Containing the rendered Field (with label etc.)
38523 * @cfg {Mixed} value A value to initialize this field with.
38528 * @cfg {String} name The field's HTML name attribute.
38531 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38534 loadedValue : false,
38538 initComponent : function(){
38539 Roo.form.Field.superclass.initComponent.call(this);
38543 * Fires when this field receives input focus.
38544 * @param {Roo.form.Field} this
38549 * Fires when this field loses input focus.
38550 * @param {Roo.form.Field} this
38554 * @event specialkey
38555 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38556 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38557 * @param {Roo.form.Field} this
38558 * @param {Roo.EventObject} e The event object
38563 * Fires just before the field blurs if the field value has changed.
38564 * @param {Roo.form.Field} this
38565 * @param {Mixed} newValue The new value
38566 * @param {Mixed} oldValue The original value
38571 * Fires after the field has been marked as invalid.
38572 * @param {Roo.form.Field} this
38573 * @param {String} msg The validation message
38578 * Fires after the field has been validated with no errors.
38579 * @param {Roo.form.Field} this
38584 * Fires after the key up
38585 * @param {Roo.form.Field} this
38586 * @param {Roo.EventObject} e The event Object
38593 * Returns the name attribute of the field if available
38594 * @return {String} name The field name
38596 getName: function(){
38597 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38601 onRender : function(ct, position){
38602 Roo.form.Field.superclass.onRender.call(this, ct, position);
38604 var cfg = this.getAutoCreate();
38606 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38608 if (!cfg.name.length) {
38611 if(this.inputType){
38612 cfg.type = this.inputType;
38614 this.el = ct.createChild(cfg, position);
38616 var type = this.el.dom.type;
38618 if(type == 'password'){
38621 this.el.addClass('x-form-'+type);
38624 this.el.dom.readOnly = true;
38626 if(this.tabIndex !== undefined){
38627 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38630 this.el.addClass([this.fieldClass, this.cls]);
38635 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38636 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38637 * @return {Roo.form.Field} this
38639 applyTo : function(target){
38640 this.allowDomMove = false;
38641 this.el = Roo.get(target);
38642 this.render(this.el.dom.parentNode);
38647 initValue : function(){
38648 if(this.value !== undefined){
38649 this.setValue(this.value);
38650 }else if(this.el.dom.value.length > 0){
38651 this.setValue(this.el.dom.value);
38656 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38657 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38659 isDirty : function() {
38660 if(this.disabled) {
38663 return String(this.getValue()) !== String(this.originalValue);
38667 * stores the current value in loadedValue
38669 resetHasChanged : function()
38671 this.loadedValue = String(this.getValue());
38674 * checks the current value against the 'loaded' value.
38675 * Note - will return false if 'resetHasChanged' has not been called first.
38677 hasChanged : function()
38679 if(this.disabled || this.readOnly) {
38682 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38688 afterRender : function(){
38689 Roo.form.Field.superclass.afterRender.call(this);
38694 fireKey : function(e){
38695 //Roo.log('field ' + e.getKey());
38696 if(e.isNavKeyPress()){
38697 this.fireEvent("specialkey", this, e);
38702 * Resets the current field value to the originally loaded value and clears any validation messages
38704 reset : function(){
38705 this.setValue(this.resetValue);
38706 this.clearInvalid();
38710 initEvents : function(){
38711 // safari killled keypress - so keydown is now used..
38712 this.el.on("keydown" , this.fireKey, this);
38713 this.el.on("focus", this.onFocus, this);
38714 this.el.on("blur", this.onBlur, this);
38715 this.el.relayEvent('keyup', this);
38717 // reference to original value for reset
38718 this.originalValue = this.getValue();
38719 this.resetValue = this.getValue();
38723 onFocus : function(){
38724 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38725 this.el.addClass(this.focusClass);
38727 if(!this.hasFocus){
38728 this.hasFocus = true;
38729 this.startValue = this.getValue();
38730 this.fireEvent("focus", this);
38734 beforeBlur : Roo.emptyFn,
38737 onBlur : function(){
38739 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38740 this.el.removeClass(this.focusClass);
38742 this.hasFocus = false;
38743 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38746 var v = this.getValue();
38747 if(String(v) !== String(this.startValue)){
38748 this.fireEvent('change', this, v, this.startValue);
38750 this.fireEvent("blur", this);
38754 * Returns whether or not the field value is currently valid
38755 * @param {Boolean} preventMark True to disable marking the field invalid
38756 * @return {Boolean} True if the value is valid, else false
38758 isValid : function(preventMark){
38762 var restore = this.preventMark;
38763 this.preventMark = preventMark === true;
38764 var v = this.validateValue(this.processValue(this.getRawValue()));
38765 this.preventMark = restore;
38770 * Validates the field value
38771 * @return {Boolean} True if the value is valid, else false
38773 validate : function(){
38774 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38775 this.clearInvalid();
38781 processValue : function(value){
38786 // Subclasses should provide the validation implementation by overriding this
38787 validateValue : function(value){
38792 * Mark this field as invalid
38793 * @param {String} msg The validation message
38795 markInvalid : function(msg){
38796 if(!this.rendered || this.preventMark){ // not rendered
38800 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38802 obj.el.addClass(this.invalidClass);
38803 msg = msg || this.invalidText;
38804 switch(this.msgTarget){
38806 obj.el.dom.qtip = msg;
38807 obj.el.dom.qclass = 'x-form-invalid-tip';
38808 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38809 Roo.QuickTips.enable();
38813 this.el.dom.title = msg;
38817 var elp = this.el.findParent('.x-form-element', 5, true);
38818 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38819 this.errorEl.setWidth(elp.getWidth(true)-20);
38821 this.errorEl.update(msg);
38822 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38825 if(!this.errorIcon){
38826 var elp = this.el.findParent('.x-form-element', 5, true);
38827 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38829 this.alignErrorIcon();
38830 this.errorIcon.dom.qtip = msg;
38831 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38832 this.errorIcon.show();
38833 this.on('resize', this.alignErrorIcon, this);
38836 var t = Roo.getDom(this.msgTarget);
38838 t.style.display = this.msgDisplay;
38841 this.fireEvent('invalid', this, msg);
38845 alignErrorIcon : function(){
38846 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
38850 * Clear any invalid styles/messages for this field
38852 clearInvalid : function(){
38853 if(!this.rendered || this.preventMark){ // not rendered
38856 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38858 obj.el.removeClass(this.invalidClass);
38859 switch(this.msgTarget){
38861 obj.el.dom.qtip = '';
38864 this.el.dom.title = '';
38868 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
38872 if(this.errorIcon){
38873 this.errorIcon.dom.qtip = '';
38874 this.errorIcon.hide();
38875 this.un('resize', this.alignErrorIcon, this);
38879 var t = Roo.getDom(this.msgTarget);
38881 t.style.display = 'none';
38884 this.fireEvent('valid', this);
38888 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
38889 * @return {Mixed} value The field value
38891 getRawValue : function(){
38892 var v = this.el.getValue();
38898 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
38899 * @return {Mixed} value The field value
38901 getValue : function(){
38902 var v = this.el.getValue();
38908 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
38909 * @param {Mixed} value The value to set
38911 setRawValue : function(v){
38912 return this.el.dom.value = (v === null || v === undefined ? '' : v);
38916 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
38917 * @param {Mixed} value The value to set
38919 setValue : function(v){
38922 this.el.dom.value = (v === null || v === undefined ? '' : v);
38927 adjustSize : function(w, h){
38928 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
38929 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
38933 adjustWidth : function(tag, w){
38934 tag = tag.toLowerCase();
38935 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
38936 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
38937 if(tag == 'input'){
38940 if(tag == 'textarea'){
38943 }else if(Roo.isOpera){
38944 if(tag == 'input'){
38947 if(tag == 'textarea'){
38957 // anything other than normal should be considered experimental
38958 Roo.form.Field.msgFx = {
38960 show: function(msgEl, f){
38961 msgEl.setDisplayed('block');
38964 hide : function(msgEl, f){
38965 msgEl.setDisplayed(false).update('');
38970 show: function(msgEl, f){
38971 msgEl.slideIn('t', {stopFx:true});
38974 hide : function(msgEl, f){
38975 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
38980 show: function(msgEl, f){
38981 msgEl.fixDisplay();
38982 msgEl.alignTo(f.el, 'tl-tr');
38983 msgEl.slideIn('l', {stopFx:true});
38986 hide : function(msgEl, f){
38987 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
38992 * Ext JS Library 1.1.1
38993 * Copyright(c) 2006-2007, Ext JS, LLC.
38995 * Originally Released Under LGPL - original licence link has changed is not relivant.
38998 * <script type="text/javascript">
39003 * @class Roo.form.TextField
39004 * @extends Roo.form.Field
39005 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39006 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39008 * Creates a new TextField
39009 * @param {Object} config Configuration options
39011 Roo.form.TextField = function(config){
39012 Roo.form.TextField.superclass.constructor.call(this, config);
39016 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39017 * according to the default logic, but this event provides a hook for the developer to apply additional
39018 * logic at runtime to resize the field if needed.
39019 * @param {Roo.form.Field} this This text field
39020 * @param {Number} width The new field width
39026 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39028 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39032 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39036 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39040 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39044 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39048 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39050 disableKeyFilter : false,
39052 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39056 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39060 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39062 maxLength : Number.MAX_VALUE,
39064 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39066 minLengthText : "The minimum length for this field is {0}",
39068 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39070 maxLengthText : "The maximum length for this field is {0}",
39072 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39074 selectOnFocus : false,
39076 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39078 blankText : "This field is required",
39080 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39081 * If available, this function will be called only after the basic validators all return true, and will be passed the
39082 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39086 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39087 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39088 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39092 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39096 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39102 initEvents : function()
39104 if (this.emptyText) {
39105 this.el.attr('placeholder', this.emptyText);
39108 Roo.form.TextField.superclass.initEvents.call(this);
39109 if(this.validationEvent == 'keyup'){
39110 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39111 this.el.on('keyup', this.filterValidation, this);
39113 else if(this.validationEvent !== false){
39114 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39117 if(this.selectOnFocus){
39118 this.on("focus", this.preFocus, this);
39121 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39122 this.el.on("keypress", this.filterKeys, this);
39125 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39126 this.el.on("click", this.autoSize, this);
39128 if(this.el.is('input[type=password]') && Roo.isSafari){
39129 this.el.on('keydown', this.SafariOnKeyDown, this);
39133 processValue : function(value){
39134 if(this.stripCharsRe){
39135 var newValue = value.replace(this.stripCharsRe, '');
39136 if(newValue !== value){
39137 this.setRawValue(newValue);
39144 filterValidation : function(e){
39145 if(!e.isNavKeyPress()){
39146 this.validationTask.delay(this.validationDelay);
39151 onKeyUp : function(e){
39152 if(!e.isNavKeyPress()){
39158 * Resets the current field value to the originally-loaded value and clears any validation messages.
39161 reset : function(){
39162 Roo.form.TextField.superclass.reset.call(this);
39168 preFocus : function(){
39170 if(this.selectOnFocus){
39171 this.el.dom.select();
39177 filterKeys : function(e){
39178 var k = e.getKey();
39179 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39182 var c = e.getCharCode(), cc = String.fromCharCode(c);
39183 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39186 if(!this.maskRe.test(cc)){
39191 setValue : function(v){
39193 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39199 * Validates a value according to the field's validation rules and marks the field as invalid
39200 * if the validation fails
39201 * @param {Mixed} value The value to validate
39202 * @return {Boolean} True if the value is valid, else false
39204 validateValue : function(value){
39205 if(value.length < 1) { // if it's blank
39206 if(this.allowBlank){
39207 this.clearInvalid();
39210 this.markInvalid(this.blankText);
39214 if(value.length < this.minLength){
39215 this.markInvalid(String.format(this.minLengthText, this.minLength));
39218 if(value.length > this.maxLength){
39219 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39223 var vt = Roo.form.VTypes;
39224 if(!vt[this.vtype](value, this)){
39225 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39229 if(typeof this.validator == "function"){
39230 var msg = this.validator(value);
39232 this.markInvalid(msg);
39236 if(this.regex && !this.regex.test(value)){
39237 this.markInvalid(this.regexText);
39244 * Selects text in this field
39245 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39246 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39248 selectText : function(start, end){
39249 var v = this.getRawValue();
39251 start = start === undefined ? 0 : start;
39252 end = end === undefined ? v.length : end;
39253 var d = this.el.dom;
39254 if(d.setSelectionRange){
39255 d.setSelectionRange(start, end);
39256 }else if(d.createTextRange){
39257 var range = d.createTextRange();
39258 range.moveStart("character", start);
39259 range.moveEnd("character", v.length-end);
39266 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39267 * This only takes effect if grow = true, and fires the autosize event.
39269 autoSize : function(){
39270 if(!this.grow || !this.rendered){
39274 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39277 var v = el.dom.value;
39278 var d = document.createElement('div');
39279 d.appendChild(document.createTextNode(v));
39283 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39284 this.el.setWidth(w);
39285 this.fireEvent("autosize", this, w);
39289 SafariOnKeyDown : function(event)
39291 // this is a workaround for a password hang bug on chrome/ webkit.
39293 var isSelectAll = false;
39295 if(this.el.dom.selectionEnd > 0){
39296 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39298 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39299 event.preventDefault();
39304 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39306 event.preventDefault();
39307 // this is very hacky as keydown always get's upper case.
39309 var cc = String.fromCharCode(event.getCharCode());
39312 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39320 * Ext JS Library 1.1.1
39321 * Copyright(c) 2006-2007, Ext JS, LLC.
39323 * Originally Released Under LGPL - original licence link has changed is not relivant.
39326 * <script type="text/javascript">
39330 * @class Roo.form.Hidden
39331 * @extends Roo.form.TextField
39332 * Simple Hidden element used on forms
39334 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39337 * Creates a new Hidden form element.
39338 * @param {Object} config Configuration options
39343 // easy hidden field...
39344 Roo.form.Hidden = function(config){
39345 Roo.form.Hidden.superclass.constructor.call(this, config);
39348 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39350 inputType: 'hidden',
39353 labelSeparator: '',
39355 itemCls : 'x-form-item-display-none'
39363 * Ext JS Library 1.1.1
39364 * Copyright(c) 2006-2007, Ext JS, LLC.
39366 * Originally Released Under LGPL - original licence link has changed is not relivant.
39369 * <script type="text/javascript">
39373 * @class Roo.form.TriggerField
39374 * @extends Roo.form.TextField
39375 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39376 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39377 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39378 * for which you can provide a custom implementation. For example:
39380 var trigger = new Roo.form.TriggerField();
39381 trigger.onTriggerClick = myTriggerFn;
39382 trigger.applyTo('my-field');
39385 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39386 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39387 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39388 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39390 * Create a new TriggerField.
39391 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39392 * to the base TextField)
39394 Roo.form.TriggerField = function(config){
39395 this.mimicing = false;
39396 Roo.form.TriggerField.superclass.constructor.call(this, config);
39399 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39401 * @cfg {String} triggerClass A CSS class to apply to the trigger
39404 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39405 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39407 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39409 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39413 /** @cfg {Boolean} grow @hide */
39414 /** @cfg {Number} growMin @hide */
39415 /** @cfg {Number} growMax @hide */
39421 autoSize: Roo.emptyFn,
39425 deferHeight : true,
39428 actionMode : 'wrap',
39430 onResize : function(w, h){
39431 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39432 if(typeof w == 'number'){
39433 var x = w - this.trigger.getWidth();
39434 this.el.setWidth(this.adjustWidth('input', x));
39435 this.trigger.setStyle('left', x+'px');
39440 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39443 getResizeEl : function(){
39448 getPositionEl : function(){
39453 alignErrorIcon : function(){
39454 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39458 onRender : function(ct, position){
39459 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39460 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39461 this.trigger = this.wrap.createChild(this.triggerConfig ||
39462 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39463 if(this.hideTrigger){
39464 this.trigger.setDisplayed(false);
39466 this.initTrigger();
39468 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39473 initTrigger : function(){
39474 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39475 this.trigger.addClassOnOver('x-form-trigger-over');
39476 this.trigger.addClassOnClick('x-form-trigger-click');
39480 onDestroy : function(){
39482 this.trigger.removeAllListeners();
39483 this.trigger.remove();
39486 this.wrap.remove();
39488 Roo.form.TriggerField.superclass.onDestroy.call(this);
39492 onFocus : function(){
39493 Roo.form.TriggerField.superclass.onFocus.call(this);
39494 if(!this.mimicing){
39495 this.wrap.addClass('x-trigger-wrap-focus');
39496 this.mimicing = true;
39497 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39498 if(this.monitorTab){
39499 this.el.on("keydown", this.checkTab, this);
39505 checkTab : function(e){
39506 if(e.getKey() == e.TAB){
39507 this.triggerBlur();
39512 onBlur : function(){
39517 mimicBlur : function(e, t){
39518 if(!this.wrap.contains(t) && this.validateBlur()){
39519 this.triggerBlur();
39524 triggerBlur : function(){
39525 this.mimicing = false;
39526 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39527 if(this.monitorTab){
39528 this.el.un("keydown", this.checkTab, this);
39530 this.wrap.removeClass('x-trigger-wrap-focus');
39531 Roo.form.TriggerField.superclass.onBlur.call(this);
39535 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39536 validateBlur : function(e, t){
39541 onDisable : function(){
39542 Roo.form.TriggerField.superclass.onDisable.call(this);
39544 this.wrap.addClass('x-item-disabled');
39549 onEnable : function(){
39550 Roo.form.TriggerField.superclass.onEnable.call(this);
39552 this.wrap.removeClass('x-item-disabled');
39557 onShow : function(){
39558 var ae = this.getActionEl();
39561 ae.dom.style.display = '';
39562 ae.dom.style.visibility = 'visible';
39568 onHide : function(){
39569 var ae = this.getActionEl();
39570 ae.dom.style.display = 'none';
39574 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39575 * by an implementing function.
39577 * @param {EventObject} e
39579 onTriggerClick : Roo.emptyFn
39582 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39583 // to be extended by an implementing class. For an example of implementing this class, see the custom
39584 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39585 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39586 initComponent : function(){
39587 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39589 this.triggerConfig = {
39590 tag:'span', cls:'x-form-twin-triggers', cn:[
39591 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39592 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39596 getTrigger : function(index){
39597 return this.triggers[index];
39600 initTrigger : function(){
39601 var ts = this.trigger.select('.x-form-trigger', true);
39602 this.wrap.setStyle('overflow', 'hidden');
39603 var triggerField = this;
39604 ts.each(function(t, all, index){
39605 t.hide = function(){
39606 var w = triggerField.wrap.getWidth();
39607 this.dom.style.display = 'none';
39608 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39610 t.show = function(){
39611 var w = triggerField.wrap.getWidth();
39612 this.dom.style.display = '';
39613 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39615 var triggerIndex = 'Trigger'+(index+1);
39617 if(this['hide'+triggerIndex]){
39618 t.dom.style.display = 'none';
39620 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39621 t.addClassOnOver('x-form-trigger-over');
39622 t.addClassOnClick('x-form-trigger-click');
39624 this.triggers = ts.elements;
39627 onTrigger1Click : Roo.emptyFn,
39628 onTrigger2Click : Roo.emptyFn
39631 * Ext JS Library 1.1.1
39632 * Copyright(c) 2006-2007, Ext JS, LLC.
39634 * Originally Released Under LGPL - original licence link has changed is not relivant.
39637 * <script type="text/javascript">
39641 * @class Roo.form.TextArea
39642 * @extends Roo.form.TextField
39643 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39644 * support for auto-sizing.
39646 * Creates a new TextArea
39647 * @param {Object} config Configuration options
39649 Roo.form.TextArea = function(config){
39650 Roo.form.TextArea.superclass.constructor.call(this, config);
39651 // these are provided exchanges for backwards compat
39652 // minHeight/maxHeight were replaced by growMin/growMax to be
39653 // compatible with TextField growing config values
39654 if(this.minHeight !== undefined){
39655 this.growMin = this.minHeight;
39657 if(this.maxHeight !== undefined){
39658 this.growMax = this.maxHeight;
39662 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39664 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39668 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39672 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39673 * in the field (equivalent to setting overflow: hidden, defaults to false)
39675 preventScrollbars: false,
39677 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39678 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39682 onRender : function(ct, position){
39684 this.defaultAutoCreate = {
39686 style:"width:300px;height:60px;",
39687 autocomplete: "new-password"
39690 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39692 this.textSizeEl = Roo.DomHelper.append(document.body, {
39693 tag: "pre", cls: "x-form-grow-sizer"
39695 if(this.preventScrollbars){
39696 this.el.setStyle("overflow", "hidden");
39698 this.el.setHeight(this.growMin);
39702 onDestroy : function(){
39703 if(this.textSizeEl){
39704 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39706 Roo.form.TextArea.superclass.onDestroy.call(this);
39710 onKeyUp : function(e){
39711 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39717 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39718 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39720 autoSize : function(){
39721 if(!this.grow || !this.textSizeEl){
39725 var v = el.dom.value;
39726 var ts = this.textSizeEl;
39729 ts.appendChild(document.createTextNode(v));
39732 Roo.fly(ts).setWidth(this.el.getWidth());
39734 v = "  ";
39737 v = v.replace(/\n/g, '<p> </p>');
39739 v += " \n ";
39742 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39743 if(h != this.lastHeight){
39744 this.lastHeight = h;
39745 this.el.setHeight(h);
39746 this.fireEvent("autosize", this, h);
39751 * Ext JS Library 1.1.1
39752 * Copyright(c) 2006-2007, Ext JS, LLC.
39754 * Originally Released Under LGPL - original licence link has changed is not relivant.
39757 * <script type="text/javascript">
39762 * @class Roo.form.NumberField
39763 * @extends Roo.form.TextField
39764 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39766 * Creates a new NumberField
39767 * @param {Object} config Configuration options
39769 Roo.form.NumberField = function(config){
39770 Roo.form.NumberField.superclass.constructor.call(this, config);
39773 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39775 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39777 fieldClass: "x-form-field x-form-num-field",
39779 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39781 allowDecimals : true,
39783 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39785 decimalSeparator : ".",
39787 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39789 decimalPrecision : 2,
39791 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39793 allowNegative : true,
39795 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39797 minValue : Number.NEGATIVE_INFINITY,
39799 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39801 maxValue : Number.MAX_VALUE,
39803 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39805 minText : "The minimum value for this field is {0}",
39807 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39809 maxText : "The maximum value for this field is {0}",
39811 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39812 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39814 nanText : "{0} is not a valid number",
39817 initEvents : function(){
39818 Roo.form.NumberField.superclass.initEvents.call(this);
39819 var allowed = "0123456789";
39820 if(this.allowDecimals){
39821 allowed += this.decimalSeparator;
39823 if(this.allowNegative){
39826 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39827 var keyPress = function(e){
39828 var k = e.getKey();
39829 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39832 var c = e.getCharCode();
39833 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39837 this.el.on("keypress", keyPress, this);
39841 validateValue : function(value){
39842 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39845 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39848 var num = this.parseValue(value);
39850 this.markInvalid(String.format(this.nanText, value));
39853 if(num < this.minValue){
39854 this.markInvalid(String.format(this.minText, this.minValue));
39857 if(num > this.maxValue){
39858 this.markInvalid(String.format(this.maxText, this.maxValue));
39864 getValue : function(){
39865 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
39869 parseValue : function(value){
39870 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
39871 return isNaN(value) ? '' : value;
39875 fixPrecision : function(value){
39876 var nan = isNaN(value);
39877 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
39878 return nan ? '' : value;
39880 return parseFloat(value).toFixed(this.decimalPrecision);
39883 setValue : function(v){
39884 v = this.fixPrecision(v);
39885 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
39889 decimalPrecisionFcn : function(v){
39890 return Math.floor(v);
39893 beforeBlur : function(){
39894 var v = this.parseValue(this.getRawValue());
39901 * Ext JS Library 1.1.1
39902 * Copyright(c) 2006-2007, Ext JS, LLC.
39904 * Originally Released Under LGPL - original licence link has changed is not relivant.
39907 * <script type="text/javascript">
39911 * @class Roo.form.DateField
39912 * @extends Roo.form.TriggerField
39913 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
39915 * Create a new DateField
39916 * @param {Object} config
39918 Roo.form.DateField = function(config){
39919 Roo.form.DateField.superclass.constructor.call(this, config);
39925 * Fires when a date is selected
39926 * @param {Roo.form.DateField} combo This combo box
39927 * @param {Date} date The date selected
39934 if(typeof this.minValue == "string") {
39935 this.minValue = this.parseDate(this.minValue);
39937 if(typeof this.maxValue == "string") {
39938 this.maxValue = this.parseDate(this.maxValue);
39940 this.ddMatch = null;
39941 if(this.disabledDates){
39942 var dd = this.disabledDates;
39944 for(var i = 0; i < dd.length; i++){
39946 if(i != dd.length-1) {
39950 this.ddMatch = new RegExp(re + ")");
39954 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
39956 * @cfg {String} format
39957 * The default date format string which can be overriden for localization support. The format must be
39958 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
39962 * @cfg {String} altFormats
39963 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
39964 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
39966 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
39968 * @cfg {Array} disabledDays
39969 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
39971 disabledDays : null,
39973 * @cfg {String} disabledDaysText
39974 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
39976 disabledDaysText : "Disabled",
39978 * @cfg {Array} disabledDates
39979 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
39980 * expression so they are very powerful. Some examples:
39982 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
39983 * <li>["03/08", "09/16"] would disable those days for every year</li>
39984 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
39985 * <li>["03/../2006"] would disable every day in March 2006</li>
39986 * <li>["^03"] would disable every day in every March</li>
39988 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
39989 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
39991 disabledDates : null,
39993 * @cfg {String} disabledDatesText
39994 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
39996 disabledDatesText : "Disabled",
39998 * @cfg {Date/String} minValue
39999 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40000 * valid format (defaults to null).
40004 * @cfg {Date/String} maxValue
40005 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40006 * valid format (defaults to null).
40010 * @cfg {String} minText
40011 * The error text to display when the date in the cell is before minValue (defaults to
40012 * 'The date in this field must be after {minValue}').
40014 minText : "The date in this field must be equal to or after {0}",
40016 * @cfg {String} maxText
40017 * The error text to display when the date in the cell is after maxValue (defaults to
40018 * 'The date in this field must be before {maxValue}').
40020 maxText : "The date in this field must be equal to or before {0}",
40022 * @cfg {String} invalidText
40023 * The error text to display when the date in the field is invalid (defaults to
40024 * '{value} is not a valid date - it must be in the format {format}').
40026 invalidText : "{0} is not a valid date - it must be in the format {1}",
40028 * @cfg {String} triggerClass
40029 * An additional CSS class used to style the trigger button. The trigger will always get the
40030 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40031 * which displays a calendar icon).
40033 triggerClass : 'x-form-date-trigger',
40037 * @cfg {Boolean} useIso
40038 * if enabled, then the date field will use a hidden field to store the
40039 * real value as iso formated date. default (false)
40043 * @cfg {String/Object} autoCreate
40044 * A DomHelper element spec, or true for a default element spec (defaults to
40045 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40048 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40051 hiddenField: false,
40053 onRender : function(ct, position)
40055 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40057 //this.el.dom.removeAttribute('name');
40058 Roo.log("Changing name?");
40059 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40060 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40062 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40063 // prevent input submission
40064 this.hiddenName = this.name;
40071 validateValue : function(value)
40073 value = this.formatDate(value);
40074 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40075 Roo.log('super failed');
40078 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40081 var svalue = value;
40082 value = this.parseDate(value);
40084 Roo.log('parse date failed' + svalue);
40085 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40088 var time = value.getTime();
40089 if(this.minValue && time < this.minValue.getTime()){
40090 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40093 if(this.maxValue && time > this.maxValue.getTime()){
40094 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40097 if(this.disabledDays){
40098 var day = value.getDay();
40099 for(var i = 0; i < this.disabledDays.length; i++) {
40100 if(day === this.disabledDays[i]){
40101 this.markInvalid(this.disabledDaysText);
40106 var fvalue = this.formatDate(value);
40107 if(this.ddMatch && this.ddMatch.test(fvalue)){
40108 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40115 // Provides logic to override the default TriggerField.validateBlur which just returns true
40116 validateBlur : function(){
40117 return !this.menu || !this.menu.isVisible();
40120 getName: function()
40122 // returns hidden if it's set..
40123 if (!this.rendered) {return ''};
40124 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40129 * Returns the current date value of the date field.
40130 * @return {Date} The date value
40132 getValue : function(){
40134 return this.hiddenField ?
40135 this.hiddenField.value :
40136 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40140 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40141 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40142 * (the default format used is "m/d/y").
40145 //All of these calls set the same date value (May 4, 2006)
40147 //Pass a date object:
40148 var dt = new Date('5/4/06');
40149 dateField.setValue(dt);
40151 //Pass a date string (default format):
40152 dateField.setValue('5/4/06');
40154 //Pass a date string (custom format):
40155 dateField.format = 'Y-m-d';
40156 dateField.setValue('2006-5-4');
40158 * @param {String/Date} date The date or valid date string
40160 setValue : function(date){
40161 if (this.hiddenField) {
40162 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40164 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40165 // make sure the value field is always stored as a date..
40166 this.value = this.parseDate(date);
40172 parseDate : function(value){
40173 if(!value || value instanceof Date){
40176 var v = Date.parseDate(value, this.format);
40177 if (!v && this.useIso) {
40178 v = Date.parseDate(value, 'Y-m-d');
40180 if(!v && this.altFormats){
40181 if(!this.altFormatsArray){
40182 this.altFormatsArray = this.altFormats.split("|");
40184 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40185 v = Date.parseDate(value, this.altFormatsArray[i]);
40192 formatDate : function(date, fmt){
40193 return (!date || !(date instanceof Date)) ?
40194 date : date.dateFormat(fmt || this.format);
40199 select: function(m, d){
40202 this.fireEvent('select', this, d);
40204 show : function(){ // retain focus styling
40208 this.focus.defer(10, this);
40209 var ml = this.menuListeners;
40210 this.menu.un("select", ml.select, this);
40211 this.menu.un("show", ml.show, this);
40212 this.menu.un("hide", ml.hide, this);
40217 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40218 onTriggerClick : function(){
40222 if(this.menu == null){
40223 this.menu = new Roo.menu.DateMenu();
40225 Roo.apply(this.menu.picker, {
40226 showClear: this.allowBlank,
40227 minDate : this.minValue,
40228 maxDate : this.maxValue,
40229 disabledDatesRE : this.ddMatch,
40230 disabledDatesText : this.disabledDatesText,
40231 disabledDays : this.disabledDays,
40232 disabledDaysText : this.disabledDaysText,
40233 format : this.useIso ? 'Y-m-d' : this.format,
40234 minText : String.format(this.minText, this.formatDate(this.minValue)),
40235 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40237 this.menu.on(Roo.apply({}, this.menuListeners, {
40240 this.menu.picker.setValue(this.getValue() || new Date());
40241 this.menu.show(this.el, "tl-bl?");
40244 beforeBlur : function(){
40245 var v = this.parseDate(this.getRawValue());
40255 isDirty : function() {
40256 if(this.disabled) {
40260 if(typeof(this.startValue) === 'undefined'){
40264 return String(this.getValue()) !== String(this.startValue);
40269 * Ext JS Library 1.1.1
40270 * Copyright(c) 2006-2007, Ext JS, LLC.
40272 * Originally Released Under LGPL - original licence link has changed is not relivant.
40275 * <script type="text/javascript">
40279 * @class Roo.form.MonthField
40280 * @extends Roo.form.TriggerField
40281 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40283 * Create a new MonthField
40284 * @param {Object} config
40286 Roo.form.MonthField = function(config){
40288 Roo.form.MonthField.superclass.constructor.call(this, config);
40294 * Fires when a date is selected
40295 * @param {Roo.form.MonthFieeld} combo This combo box
40296 * @param {Date} date The date selected
40303 if(typeof this.minValue == "string") {
40304 this.minValue = this.parseDate(this.minValue);
40306 if(typeof this.maxValue == "string") {
40307 this.maxValue = this.parseDate(this.maxValue);
40309 this.ddMatch = null;
40310 if(this.disabledDates){
40311 var dd = this.disabledDates;
40313 for(var i = 0; i < dd.length; i++){
40315 if(i != dd.length-1) {
40319 this.ddMatch = new RegExp(re + ")");
40323 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40325 * @cfg {String} format
40326 * The default date format string which can be overriden for localization support. The format must be
40327 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40331 * @cfg {String} altFormats
40332 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40333 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40335 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40337 * @cfg {Array} disabledDays
40338 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40340 disabledDays : [0,1,2,3,4,5,6],
40342 * @cfg {String} disabledDaysText
40343 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40345 disabledDaysText : "Disabled",
40347 * @cfg {Array} disabledDates
40348 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40349 * expression so they are very powerful. Some examples:
40351 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40352 * <li>["03/08", "09/16"] would disable those days for every year</li>
40353 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40354 * <li>["03/../2006"] would disable every day in March 2006</li>
40355 * <li>["^03"] would disable every day in every March</li>
40357 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40358 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40360 disabledDates : null,
40362 * @cfg {String} disabledDatesText
40363 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40365 disabledDatesText : "Disabled",
40367 * @cfg {Date/String} minValue
40368 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40369 * valid format (defaults to null).
40373 * @cfg {Date/String} maxValue
40374 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40375 * valid format (defaults to null).
40379 * @cfg {String} minText
40380 * The error text to display when the date in the cell is before minValue (defaults to
40381 * 'The date in this field must be after {minValue}').
40383 minText : "The date in this field must be equal to or after {0}",
40385 * @cfg {String} maxTextf
40386 * The error text to display when the date in the cell is after maxValue (defaults to
40387 * 'The date in this field must be before {maxValue}').
40389 maxText : "The date in this field must be equal to or before {0}",
40391 * @cfg {String} invalidText
40392 * The error text to display when the date in the field is invalid (defaults to
40393 * '{value} is not a valid date - it must be in the format {format}').
40395 invalidText : "{0} is not a valid date - it must be in the format {1}",
40397 * @cfg {String} triggerClass
40398 * An additional CSS class used to style the trigger button. The trigger will always get the
40399 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40400 * which displays a calendar icon).
40402 triggerClass : 'x-form-date-trigger',
40406 * @cfg {Boolean} useIso
40407 * if enabled, then the date field will use a hidden field to store the
40408 * real value as iso formated date. default (true)
40412 * @cfg {String/Object} autoCreate
40413 * A DomHelper element spec, or true for a default element spec (defaults to
40414 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40417 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40420 hiddenField: false,
40422 hideMonthPicker : false,
40424 onRender : function(ct, position)
40426 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40428 this.el.dom.removeAttribute('name');
40429 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40431 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40432 // prevent input submission
40433 this.hiddenName = this.name;
40440 validateValue : function(value)
40442 value = this.formatDate(value);
40443 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40446 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40449 var svalue = value;
40450 value = this.parseDate(value);
40452 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40455 var time = value.getTime();
40456 if(this.minValue && time < this.minValue.getTime()){
40457 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40460 if(this.maxValue && time > this.maxValue.getTime()){
40461 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40464 /*if(this.disabledDays){
40465 var day = value.getDay();
40466 for(var i = 0; i < this.disabledDays.length; i++) {
40467 if(day === this.disabledDays[i]){
40468 this.markInvalid(this.disabledDaysText);
40474 var fvalue = this.formatDate(value);
40475 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40476 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40484 // Provides logic to override the default TriggerField.validateBlur which just returns true
40485 validateBlur : function(){
40486 return !this.menu || !this.menu.isVisible();
40490 * Returns the current date value of the date field.
40491 * @return {Date} The date value
40493 getValue : function(){
40497 return this.hiddenField ?
40498 this.hiddenField.value :
40499 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40503 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40504 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40505 * (the default format used is "m/d/y").
40508 //All of these calls set the same date value (May 4, 2006)
40510 //Pass a date object:
40511 var dt = new Date('5/4/06');
40512 monthField.setValue(dt);
40514 //Pass a date string (default format):
40515 monthField.setValue('5/4/06');
40517 //Pass a date string (custom format):
40518 monthField.format = 'Y-m-d';
40519 monthField.setValue('2006-5-4');
40521 * @param {String/Date} date The date or valid date string
40523 setValue : function(date){
40524 Roo.log('month setValue' + date);
40525 // can only be first of month..
40527 var val = this.parseDate(date);
40529 if (this.hiddenField) {
40530 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40532 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40533 this.value = this.parseDate(date);
40537 parseDate : function(value){
40538 if(!value || value instanceof Date){
40539 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40542 var v = Date.parseDate(value, this.format);
40543 if (!v && this.useIso) {
40544 v = Date.parseDate(value, 'Y-m-d');
40548 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40552 if(!v && this.altFormats){
40553 if(!this.altFormatsArray){
40554 this.altFormatsArray = this.altFormats.split("|");
40556 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40557 v = Date.parseDate(value, this.altFormatsArray[i]);
40564 formatDate : function(date, fmt){
40565 return (!date || !(date instanceof Date)) ?
40566 date : date.dateFormat(fmt || this.format);
40571 select: function(m, d){
40573 this.fireEvent('select', this, d);
40575 show : function(){ // retain focus styling
40579 this.focus.defer(10, this);
40580 var ml = this.menuListeners;
40581 this.menu.un("select", ml.select, this);
40582 this.menu.un("show", ml.show, this);
40583 this.menu.un("hide", ml.hide, this);
40587 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40588 onTriggerClick : function(){
40592 if(this.menu == null){
40593 this.menu = new Roo.menu.DateMenu();
40597 Roo.apply(this.menu.picker, {
40599 showClear: this.allowBlank,
40600 minDate : this.minValue,
40601 maxDate : this.maxValue,
40602 disabledDatesRE : this.ddMatch,
40603 disabledDatesText : this.disabledDatesText,
40605 format : this.useIso ? 'Y-m-d' : this.format,
40606 minText : String.format(this.minText, this.formatDate(this.minValue)),
40607 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40610 this.menu.on(Roo.apply({}, this.menuListeners, {
40618 // hide month picker get's called when we called by 'before hide';
40620 var ignorehide = true;
40621 p.hideMonthPicker = function(disableAnim){
40625 if(this.monthPicker){
40626 Roo.log("hideMonthPicker called");
40627 if(disableAnim === true){
40628 this.monthPicker.hide();
40630 this.monthPicker.slideOut('t', {duration:.2});
40631 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40632 p.fireEvent("select", this, this.value);
40638 Roo.log('picker set value');
40639 Roo.log(this.getValue());
40640 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40641 m.show(this.el, 'tl-bl?');
40642 ignorehide = false;
40643 // this will trigger hideMonthPicker..
40646 // hidden the day picker
40647 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40653 p.showMonthPicker.defer(100, p);
40659 beforeBlur : function(){
40660 var v = this.parseDate(this.getRawValue());
40666 /** @cfg {Boolean} grow @hide */
40667 /** @cfg {Number} growMin @hide */
40668 /** @cfg {Number} growMax @hide */
40675 * Ext JS Library 1.1.1
40676 * Copyright(c) 2006-2007, Ext JS, LLC.
40678 * Originally Released Under LGPL - original licence link has changed is not relivant.
40681 * <script type="text/javascript">
40686 * @class Roo.form.ComboBox
40687 * @extends Roo.form.TriggerField
40688 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40690 * Create a new ComboBox.
40691 * @param {Object} config Configuration options
40693 Roo.form.ComboBox = function(config){
40694 Roo.form.ComboBox.superclass.constructor.call(this, config);
40698 * Fires when the dropdown list is expanded
40699 * @param {Roo.form.ComboBox} combo This combo box
40704 * Fires when the dropdown list is collapsed
40705 * @param {Roo.form.ComboBox} combo This combo box
40709 * @event beforeselect
40710 * Fires before a list item is selected. Return false to cancel the selection.
40711 * @param {Roo.form.ComboBox} combo This combo box
40712 * @param {Roo.data.Record} record The data record returned from the underlying store
40713 * @param {Number} index The index of the selected item in the dropdown list
40715 'beforeselect' : true,
40718 * Fires when a list item is selected
40719 * @param {Roo.form.ComboBox} combo This combo box
40720 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40721 * @param {Number} index The index of the selected item in the dropdown list
40725 * @event beforequery
40726 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40727 * The event object passed has these properties:
40728 * @param {Roo.form.ComboBox} combo This combo box
40729 * @param {String} query The query
40730 * @param {Boolean} forceAll true to force "all" query
40731 * @param {Boolean} cancel true to cancel the query
40732 * @param {Object} e The query event object
40734 'beforequery': true,
40737 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40738 * @param {Roo.form.ComboBox} combo This combo box
40743 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40744 * @param {Roo.form.ComboBox} combo This combo box
40745 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40751 if(this.transform){
40752 this.allowDomMove = false;
40753 var s = Roo.getDom(this.transform);
40754 if(!this.hiddenName){
40755 this.hiddenName = s.name;
40758 this.mode = 'local';
40759 var d = [], opts = s.options;
40760 for(var i = 0, len = opts.length;i < len; i++){
40762 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40764 this.value = value;
40766 d.push([value, o.text]);
40768 this.store = new Roo.data.SimpleStore({
40770 fields: ['value', 'text'],
40773 this.valueField = 'value';
40774 this.displayField = 'text';
40776 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40777 if(!this.lazyRender){
40778 this.target = true;
40779 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40780 s.parentNode.removeChild(s); // remove it
40781 this.render(this.el.parentNode);
40783 s.parentNode.removeChild(s); // remove it
40788 this.store = Roo.factory(this.store, Roo.data);
40791 this.selectedIndex = -1;
40792 if(this.mode == 'local'){
40793 if(config.queryDelay === undefined){
40794 this.queryDelay = 10;
40796 if(config.minChars === undefined){
40802 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40804 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40807 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40808 * rendering into an Roo.Editor, defaults to false)
40811 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40812 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40815 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40818 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40819 * the dropdown list (defaults to undefined, with no header element)
40823 * @cfg {String/Roo.Template} tpl The template to use to render the output
40827 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40829 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40831 listWidth: undefined,
40833 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40834 * mode = 'remote' or 'text' if mode = 'local')
40836 displayField: undefined,
40838 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40839 * mode = 'remote' or 'value' if mode = 'local').
40840 * Note: use of a valueField requires the user make a selection
40841 * in order for a value to be mapped.
40843 valueField: undefined,
40847 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
40848 * field's data value (defaults to the underlying DOM element's name)
40850 hiddenName: undefined,
40852 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
40856 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
40858 selectedClass: 'x-combo-selected',
40860 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40861 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
40862 * which displays a downward arrow icon).
40864 triggerClass : 'x-form-arrow-trigger',
40866 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
40870 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
40871 * anchor positions (defaults to 'tl-bl')
40873 listAlign: 'tl-bl?',
40875 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
40879 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
40880 * query specified by the allQuery config option (defaults to 'query')
40882 triggerAction: 'query',
40884 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
40885 * (defaults to 4, does not apply if editable = false)
40889 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
40890 * delay (typeAheadDelay) if it matches a known value (defaults to false)
40894 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
40895 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
40899 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
40900 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
40904 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
40905 * when editable = true (defaults to false)
40907 selectOnFocus:false,
40909 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
40911 queryParam: 'query',
40913 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
40914 * when mode = 'remote' (defaults to 'Loading...')
40916 loadingText: 'Loading...',
40918 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
40922 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
40926 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
40927 * traditional select (defaults to true)
40931 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
40935 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
40939 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
40940 * listWidth has a higher value)
40944 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
40945 * allow the user to set arbitrary text into the field (defaults to false)
40947 forceSelection:false,
40949 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
40950 * if typeAhead = true (defaults to 250)
40952 typeAheadDelay : 250,
40954 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
40955 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
40957 valueNotFoundText : undefined,
40959 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
40961 blockFocus : false,
40964 * @cfg {Boolean} disableClear Disable showing of clear button.
40966 disableClear : false,
40968 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
40970 alwaysQuery : false,
40976 // element that contains real text value.. (when hidden is used..)
40979 onRender : function(ct, position){
40980 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
40981 if(this.hiddenName){
40982 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
40984 this.hiddenField.value =
40985 this.hiddenValue !== undefined ? this.hiddenValue :
40986 this.value !== undefined ? this.value : '';
40988 // prevent input submission
40989 this.el.dom.removeAttribute('name');
40994 this.el.dom.setAttribute('autocomplete', 'off');
40997 var cls = 'x-combo-list';
40999 this.list = new Roo.Layer({
41000 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41003 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41004 this.list.setWidth(lw);
41005 this.list.swallowEvent('mousewheel');
41006 this.assetHeight = 0;
41009 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41010 this.assetHeight += this.header.getHeight();
41013 this.innerList = this.list.createChild({cls:cls+'-inner'});
41014 this.innerList.on('mouseover', this.onViewOver, this);
41015 this.innerList.on('mousemove', this.onViewMove, this);
41016 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41018 if(this.allowBlank && !this.pageSize && !this.disableClear){
41019 this.footer = this.list.createChild({cls:cls+'-ft'});
41020 this.pageTb = new Roo.Toolbar(this.footer);
41024 this.footer = this.list.createChild({cls:cls+'-ft'});
41025 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41026 {pageSize: this.pageSize});
41030 if (this.pageTb && this.allowBlank && !this.disableClear) {
41032 this.pageTb.add(new Roo.Toolbar.Fill(), {
41033 cls: 'x-btn-icon x-btn-clear',
41035 handler: function()
41038 _this.clearValue();
41039 _this.onSelect(false, -1);
41044 this.assetHeight += this.footer.getHeight();
41049 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41052 this.view = new Roo.View(this.innerList, this.tpl, {
41053 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41056 this.view.on('click', this.onViewClick, this);
41058 this.store.on('beforeload', this.onBeforeLoad, this);
41059 this.store.on('load', this.onLoad, this);
41060 this.store.on('loadexception', this.onLoadException, this);
41062 if(this.resizable){
41063 this.resizer = new Roo.Resizable(this.list, {
41064 pinned:true, handles:'se'
41066 this.resizer.on('resize', function(r, w, h){
41067 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41068 this.listWidth = w;
41069 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41070 this.restrictHeight();
41072 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41074 if(!this.editable){
41075 this.editable = true;
41076 this.setEditable(false);
41080 if (typeof(this.events.add.listeners) != 'undefined') {
41082 this.addicon = this.wrap.createChild(
41083 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41085 this.addicon.on('click', function(e) {
41086 this.fireEvent('add', this);
41089 if (typeof(this.events.edit.listeners) != 'undefined') {
41091 this.editicon = this.wrap.createChild(
41092 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41093 if (this.addicon) {
41094 this.editicon.setStyle('margin-left', '40px');
41096 this.editicon.on('click', function(e) {
41098 // we fire even if inothing is selected..
41099 this.fireEvent('edit', this, this.lastData );
41109 initEvents : function(){
41110 Roo.form.ComboBox.superclass.initEvents.call(this);
41112 this.keyNav = new Roo.KeyNav(this.el, {
41113 "up" : function(e){
41114 this.inKeyMode = true;
41118 "down" : function(e){
41119 if(!this.isExpanded()){
41120 this.onTriggerClick();
41122 this.inKeyMode = true;
41127 "enter" : function(e){
41128 this.onViewClick();
41132 "esc" : function(e){
41136 "tab" : function(e){
41137 this.onViewClick(false);
41138 this.fireEvent("specialkey", this, e);
41144 doRelay : function(foo, bar, hname){
41145 if(hname == 'down' || this.scope.isExpanded()){
41146 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41153 this.queryDelay = Math.max(this.queryDelay || 10,
41154 this.mode == 'local' ? 10 : 250);
41155 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41156 if(this.typeAhead){
41157 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41159 if(this.editable !== false){
41160 this.el.on("keyup", this.onKeyUp, this);
41162 if(this.forceSelection){
41163 this.on('blur', this.doForce, this);
41167 onDestroy : function(){
41169 this.view.setStore(null);
41170 this.view.el.removeAllListeners();
41171 this.view.el.remove();
41172 this.view.purgeListeners();
41175 this.list.destroy();
41178 this.store.un('beforeload', this.onBeforeLoad, this);
41179 this.store.un('load', this.onLoad, this);
41180 this.store.un('loadexception', this.onLoadException, this);
41182 Roo.form.ComboBox.superclass.onDestroy.call(this);
41186 fireKey : function(e){
41187 if(e.isNavKeyPress() && !this.list.isVisible()){
41188 this.fireEvent("specialkey", this, e);
41193 onResize: function(w, h){
41194 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41196 if(typeof w != 'number'){
41197 // we do not handle it!?!?
41200 var tw = this.trigger.getWidth();
41201 tw += this.addicon ? this.addicon.getWidth() : 0;
41202 tw += this.editicon ? this.editicon.getWidth() : 0;
41204 this.el.setWidth( this.adjustWidth('input', x));
41206 this.trigger.setStyle('left', x+'px');
41208 if(this.list && this.listWidth === undefined){
41209 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41210 this.list.setWidth(lw);
41211 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41219 * Allow or prevent the user from directly editing the field text. If false is passed,
41220 * the user will only be able to select from the items defined in the dropdown list. This method
41221 * is the runtime equivalent of setting the 'editable' config option at config time.
41222 * @param {Boolean} value True to allow the user to directly edit the field text
41224 setEditable : function(value){
41225 if(value == this.editable){
41228 this.editable = value;
41230 this.el.dom.setAttribute('readOnly', true);
41231 this.el.on('mousedown', this.onTriggerClick, this);
41232 this.el.addClass('x-combo-noedit');
41234 this.el.dom.setAttribute('readOnly', false);
41235 this.el.un('mousedown', this.onTriggerClick, this);
41236 this.el.removeClass('x-combo-noedit');
41241 onBeforeLoad : function(){
41242 if(!this.hasFocus){
41245 this.innerList.update(this.loadingText ?
41246 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41247 this.restrictHeight();
41248 this.selectedIndex = -1;
41252 onLoad : function(){
41253 if(!this.hasFocus){
41256 if(this.store.getCount() > 0){
41258 this.restrictHeight();
41259 if(this.lastQuery == this.allQuery){
41261 this.el.dom.select();
41263 if(!this.selectByValue(this.value, true)){
41264 this.select(0, true);
41268 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41269 this.taTask.delay(this.typeAheadDelay);
41273 this.onEmptyResults();
41278 onLoadException : function()
41281 Roo.log(this.store.reader.jsonData);
41282 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41283 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41289 onTypeAhead : function(){
41290 if(this.store.getCount() > 0){
41291 var r = this.store.getAt(0);
41292 var newValue = r.data[this.displayField];
41293 var len = newValue.length;
41294 var selStart = this.getRawValue().length;
41295 if(selStart != len){
41296 this.setRawValue(newValue);
41297 this.selectText(selStart, newValue.length);
41303 onSelect : function(record, index){
41304 if(this.fireEvent('beforeselect', this, record, index) !== false){
41305 this.setFromData(index > -1 ? record.data : false);
41307 this.fireEvent('select', this, record, index);
41312 * Returns the currently selected field value or empty string if no value is set.
41313 * @return {String} value The selected value
41315 getValue : function(){
41316 if(this.valueField){
41317 return typeof this.value != 'undefined' ? this.value : '';
41319 return Roo.form.ComboBox.superclass.getValue.call(this);
41323 * Clears any text/value currently set in the field
41325 clearValue : function(){
41326 if(this.hiddenField){
41327 this.hiddenField.value = '';
41330 this.setRawValue('');
41331 this.lastSelectionText = '';
41336 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41337 * will be displayed in the field. If the value does not match the data value of an existing item,
41338 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41339 * Otherwise the field will be blank (although the value will still be set).
41340 * @param {String} value The value to match
41342 setValue : function(v){
41344 if(this.valueField){
41345 var r = this.findRecord(this.valueField, v);
41347 text = r.data[this.displayField];
41348 }else if(this.valueNotFoundText !== undefined){
41349 text = this.valueNotFoundText;
41352 this.lastSelectionText = text;
41353 if(this.hiddenField){
41354 this.hiddenField.value = v;
41356 Roo.form.ComboBox.superclass.setValue.call(this, text);
41360 * @property {Object} the last set data for the element
41365 * Sets the value of the field based on a object which is related to the record format for the store.
41366 * @param {Object} value the value to set as. or false on reset?
41368 setFromData : function(o){
41369 var dv = ''; // display value
41370 var vv = ''; // value value..
41372 if (this.displayField) {
41373 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41375 // this is an error condition!!!
41376 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41379 if(this.valueField){
41380 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41382 if(this.hiddenField){
41383 this.hiddenField.value = vv;
41385 this.lastSelectionText = dv;
41386 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41390 // no hidden field.. - we store the value in 'value', but still display
41391 // display field!!!!
41392 this.lastSelectionText = dv;
41393 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41399 reset : function(){
41400 // overridden so that last data is reset..
41401 this.setValue(this.resetValue);
41402 this.clearInvalid();
41403 this.lastData = false;
41405 this.view.clearSelections();
41409 findRecord : function(prop, value){
41411 if(this.store.getCount() > 0){
41412 this.store.each(function(r){
41413 if(r.data[prop] == value){
41423 getName: function()
41425 // returns hidden if it's set..
41426 if (!this.rendered) {return ''};
41427 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41431 onViewMove : function(e, t){
41432 this.inKeyMode = false;
41436 onViewOver : function(e, t){
41437 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41440 var item = this.view.findItemFromChild(t);
41442 var index = this.view.indexOf(item);
41443 this.select(index, false);
41448 onViewClick : function(doFocus)
41450 var index = this.view.getSelectedIndexes()[0];
41451 var r = this.store.getAt(index);
41453 this.onSelect(r, index);
41455 if(doFocus !== false && !this.blockFocus){
41461 restrictHeight : function(){
41462 this.innerList.dom.style.height = '';
41463 var inner = this.innerList.dom;
41464 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41465 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41466 this.list.beginUpdate();
41467 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41468 this.list.alignTo(this.el, this.listAlign);
41469 this.list.endUpdate();
41473 onEmptyResults : function(){
41478 * Returns true if the dropdown list is expanded, else false.
41480 isExpanded : function(){
41481 return this.list.isVisible();
41485 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41486 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41487 * @param {String} value The data value of the item to select
41488 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41489 * selected item if it is not currently in view (defaults to true)
41490 * @return {Boolean} True if the value matched an item in the list, else false
41492 selectByValue : function(v, scrollIntoView){
41493 if(v !== undefined && v !== null){
41494 var r = this.findRecord(this.valueField || this.displayField, v);
41496 this.select(this.store.indexOf(r), scrollIntoView);
41504 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41505 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41506 * @param {Number} index The zero-based index of the list item to select
41507 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41508 * selected item if it is not currently in view (defaults to true)
41510 select : function(index, scrollIntoView){
41511 this.selectedIndex = index;
41512 this.view.select(index);
41513 if(scrollIntoView !== false){
41514 var el = this.view.getNode(index);
41516 this.innerList.scrollChildIntoView(el, false);
41522 selectNext : function(){
41523 var ct = this.store.getCount();
41525 if(this.selectedIndex == -1){
41527 }else if(this.selectedIndex < ct-1){
41528 this.select(this.selectedIndex+1);
41534 selectPrev : function(){
41535 var ct = this.store.getCount();
41537 if(this.selectedIndex == -1){
41539 }else if(this.selectedIndex != 0){
41540 this.select(this.selectedIndex-1);
41546 onKeyUp : function(e){
41547 if(this.editable !== false && !e.isSpecialKey()){
41548 this.lastKey = e.getKey();
41549 this.dqTask.delay(this.queryDelay);
41554 validateBlur : function(){
41555 return !this.list || !this.list.isVisible();
41559 initQuery : function(){
41560 this.doQuery(this.getRawValue());
41564 doForce : function(){
41565 if(this.el.dom.value.length > 0){
41566 this.el.dom.value =
41567 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41573 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41574 * query allowing the query action to be canceled if needed.
41575 * @param {String} query The SQL query to execute
41576 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41577 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41578 * saved in the current store (defaults to false)
41580 doQuery : function(q, forceAll){
41581 if(q === undefined || q === null){
41586 forceAll: forceAll,
41590 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41594 forceAll = qe.forceAll;
41595 if(forceAll === true || (q.length >= this.minChars)){
41596 if(this.lastQuery != q || this.alwaysQuery){
41597 this.lastQuery = q;
41598 if(this.mode == 'local'){
41599 this.selectedIndex = -1;
41601 this.store.clearFilter();
41603 this.store.filter(this.displayField, q);
41607 this.store.baseParams[this.queryParam] = q;
41609 params: this.getParams(q)
41614 this.selectedIndex = -1;
41621 getParams : function(q){
41623 //p[this.queryParam] = q;
41626 p.limit = this.pageSize;
41632 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41634 collapse : function(){
41635 if(!this.isExpanded()){
41639 Roo.get(document).un('mousedown', this.collapseIf, this);
41640 Roo.get(document).un('mousewheel', this.collapseIf, this);
41641 if (!this.editable) {
41642 Roo.get(document).un('keydown', this.listKeyPress, this);
41644 this.fireEvent('collapse', this);
41648 collapseIf : function(e){
41649 if(!e.within(this.wrap) && !e.within(this.list)){
41655 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41657 expand : function(){
41658 if(this.isExpanded() || !this.hasFocus){
41661 this.list.alignTo(this.el, this.listAlign);
41663 Roo.get(document).on('mousedown', this.collapseIf, this);
41664 Roo.get(document).on('mousewheel', this.collapseIf, this);
41665 if (!this.editable) {
41666 Roo.get(document).on('keydown', this.listKeyPress, this);
41669 this.fireEvent('expand', this);
41673 // Implements the default empty TriggerField.onTriggerClick function
41674 onTriggerClick : function(){
41678 if(this.isExpanded()){
41680 if (!this.blockFocus) {
41685 this.hasFocus = true;
41686 if(this.triggerAction == 'all') {
41687 this.doQuery(this.allQuery, true);
41689 this.doQuery(this.getRawValue());
41691 if (!this.blockFocus) {
41696 listKeyPress : function(e)
41698 //Roo.log('listkeypress');
41699 // scroll to first matching element based on key pres..
41700 if (e.isSpecialKey()) {
41703 var k = String.fromCharCode(e.getKey()).toUpperCase();
41706 var csel = this.view.getSelectedNodes();
41707 var cselitem = false;
41709 var ix = this.view.indexOf(csel[0]);
41710 cselitem = this.store.getAt(ix);
41711 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41717 this.store.each(function(v) {
41719 // start at existing selection.
41720 if (cselitem.id == v.id) {
41726 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41727 match = this.store.indexOf(v);
41732 if (match === false) {
41733 return true; // no more action?
41736 this.view.select(match);
41737 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41738 sn.scrollIntoView(sn.dom.parentNode, false);
41742 * @cfg {Boolean} grow
41746 * @cfg {Number} growMin
41750 * @cfg {Number} growMax
41758 * Copyright(c) 2010-2012, Roo J Solutions Limited
41765 * @class Roo.form.ComboBoxArray
41766 * @extends Roo.form.TextField
41767 * A facebook style adder... for lists of email / people / countries etc...
41768 * pick multiple items from a combo box, and shows each one.
41770 * Fred [x] Brian [x] [Pick another |v]
41773 * For this to work: it needs various extra information
41774 * - normal combo problay has
41776 * + displayField, valueField
41778 * For our purpose...
41781 * If we change from 'extends' to wrapping...
41788 * Create a new ComboBoxArray.
41789 * @param {Object} config Configuration options
41793 Roo.form.ComboBoxArray = function(config)
41797 * @event beforeremove
41798 * Fires before 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
41802 'beforeremove' : true,
41805 * Fires when remove the value from the list
41806 * @param {Roo.form.ComboBoxArray} _self This combo box array
41807 * @param {Roo.form.ComboBoxArray.Item} item removed item
41814 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41816 this.items = new Roo.util.MixedCollection(false);
41818 // construct the child combo...
41828 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41831 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41836 // behavies liek a hiddne field
41837 inputType: 'hidden',
41839 * @cfg {Number} width The width of the box that displays the selected element
41846 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
41850 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
41852 hiddenName : false,
41855 // private the array of items that are displayed..
41857 // private - the hidden field el.
41859 // private - the filed el..
41862 //validateValue : function() { return true; }, // all values are ok!
41863 //onAddClick: function() { },
41865 onRender : function(ct, position)
41868 // create the standard hidden element
41869 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
41872 // give fake names to child combo;
41873 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
41874 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
41876 this.combo = Roo.factory(this.combo, Roo.form);
41877 this.combo.onRender(ct, position);
41878 if (typeof(this.combo.width) != 'undefined') {
41879 this.combo.onResize(this.combo.width,0);
41882 this.combo.initEvents();
41884 // assigned so form know we need to do this..
41885 this.store = this.combo.store;
41886 this.valueField = this.combo.valueField;
41887 this.displayField = this.combo.displayField ;
41890 this.combo.wrap.addClass('x-cbarray-grp');
41892 var cbwrap = this.combo.wrap.createChild(
41893 {tag: 'div', cls: 'x-cbarray-cb'},
41898 this.hiddenEl = this.combo.wrap.createChild({
41899 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
41901 this.el = this.combo.wrap.createChild({
41902 tag: 'input', type:'hidden' , name: this.name, value : ''
41904 // this.el.dom.removeAttribute("name");
41907 this.outerWrap = this.combo.wrap;
41908 this.wrap = cbwrap;
41910 this.outerWrap.setWidth(this.width);
41911 this.outerWrap.dom.removeChild(this.el.dom);
41913 this.wrap.dom.appendChild(this.el.dom);
41914 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
41915 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
41917 this.combo.trigger.setStyle('position','relative');
41918 this.combo.trigger.setStyle('left', '0px');
41919 this.combo.trigger.setStyle('top', '2px');
41921 this.combo.el.setStyle('vertical-align', 'text-bottom');
41923 //this.trigger.setStyle('vertical-align', 'top');
41925 // this should use the code from combo really... on('add' ....)
41929 this.adder = this.outerWrap.createChild(
41930 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
41932 this.adder.on('click', function(e) {
41933 _t.fireEvent('adderclick', this, e);
41937 //this.adder.on('click', this.onAddClick, _t);
41940 this.combo.on('select', function(cb, rec, ix) {
41941 this.addItem(rec.data);
41944 cb.el.dom.value = '';
41945 //cb.lastData = rec.data;
41954 getName: function()
41956 // returns hidden if it's set..
41957 if (!this.rendered) {return ''};
41958 return this.hiddenName ? this.hiddenName : this.name;
41963 onResize: function(w, h){
41966 // not sure if this is needed..
41967 //this.combo.onResize(w,h);
41969 if(typeof w != 'number'){
41970 // we do not handle it!?!?
41973 var tw = this.combo.trigger.getWidth();
41974 tw += this.addicon ? this.addicon.getWidth() : 0;
41975 tw += this.editicon ? this.editicon.getWidth() : 0;
41977 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
41979 this.combo.trigger.setStyle('left', '0px');
41981 if(this.list && this.listWidth === undefined){
41982 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
41983 this.list.setWidth(lw);
41984 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41991 addItem: function(rec)
41993 var valueField = this.combo.valueField;
41994 var displayField = this.combo.displayField;
41995 if (this.items.indexOfKey(rec[valueField]) > -1) {
41996 //console.log("GOT " + rec.data.id);
42000 var x = new Roo.form.ComboBoxArray.Item({
42001 //id : rec[this.idField],
42003 displayField : displayField ,
42004 tipField : displayField ,
42008 this.items.add(rec[valueField],x);
42009 // add it before the element..
42010 this.updateHiddenEl();
42011 x.render(this.outerWrap, this.wrap.dom);
42012 // add the image handler..
42015 updateHiddenEl : function()
42018 if (!this.hiddenEl) {
42022 var idField = this.combo.valueField;
42024 this.items.each(function(f) {
42025 ar.push(f.data[idField]);
42028 this.hiddenEl.dom.value = ar.join(',');
42034 this.items.clear();
42036 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42040 this.el.dom.value = '';
42041 if (this.hiddenEl) {
42042 this.hiddenEl.dom.value = '';
42046 getValue: function()
42048 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42050 setValue: function(v) // not a valid action - must use addItems..
42057 if (this.store.isLocal && (typeof(v) == 'string')) {
42058 // then we can use the store to find the values..
42059 // comma seperated at present.. this needs to allow JSON based encoding..
42060 this.hiddenEl.value = v;
42062 Roo.each(v.split(','), function(k) {
42063 Roo.log("CHECK " + this.valueField + ',' + k);
42064 var li = this.store.query(this.valueField, k);
42069 add[this.valueField] = k;
42070 add[this.displayField] = li.item(0).data[this.displayField];
42076 if (typeof(v) == 'object' ) {
42077 // then let's assume it's an array of objects..
42078 Roo.each(v, function(l) {
42086 setFromData: function(v)
42088 // this recieves an object, if setValues is called.
42090 this.el.dom.value = v[this.displayField];
42091 this.hiddenEl.dom.value = v[this.valueField];
42092 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42095 var kv = v[this.valueField];
42096 var dv = v[this.displayField];
42097 kv = typeof(kv) != 'string' ? '' : kv;
42098 dv = typeof(dv) != 'string' ? '' : dv;
42101 var keys = kv.split(',');
42102 var display = dv.split(',');
42103 for (var i = 0 ; i < keys.length; i++) {
42106 add[this.valueField] = keys[i];
42107 add[this.displayField] = display[i];
42115 * Validates the combox array value
42116 * @return {Boolean} True if the value is valid, else false
42118 validate : function(){
42119 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42120 this.clearInvalid();
42126 validateValue : function(value){
42127 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42135 isDirty : function() {
42136 if(this.disabled) {
42141 var d = Roo.decode(String(this.originalValue));
42143 return String(this.getValue()) !== String(this.originalValue);
42146 var originalValue = [];
42148 for (var i = 0; i < d.length; i++){
42149 originalValue.push(d[i][this.valueField]);
42152 return String(this.getValue()) !== String(originalValue.join(','));
42161 * @class Roo.form.ComboBoxArray.Item
42162 * @extends Roo.BoxComponent
42163 * A selected item in the list
42164 * Fred [x] Brian [x] [Pick another |v]
42167 * Create a new item.
42168 * @param {Object} config Configuration options
42171 Roo.form.ComboBoxArray.Item = function(config) {
42172 config.id = Roo.id();
42173 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42176 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42179 displayField : false,
42183 defaultAutoCreate : {
42185 cls: 'x-cbarray-item',
42192 src : Roo.BLANK_IMAGE_URL ,
42200 onRender : function(ct, position)
42202 Roo.form.Field.superclass.onRender.call(this, ct, position);
42205 var cfg = this.getAutoCreate();
42206 this.el = ct.createChild(cfg, position);
42209 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42211 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42212 this.cb.renderer(this.data) :
42213 String.format('{0}',this.data[this.displayField]);
42216 this.el.child('div').dom.setAttribute('qtip',
42217 String.format('{0}',this.data[this.tipField])
42220 this.el.child('img').on('click', this.remove, this);
42224 remove : function()
42226 if(this.cb.disabled){
42230 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42231 this.cb.items.remove(this);
42232 this.el.child('img').un('click', this.remove, this);
42234 this.cb.updateHiddenEl();
42236 this.cb.fireEvent('remove', this.cb, this);
42242 * Ext JS Library 1.1.1
42243 * Copyright(c) 2006-2007, Ext JS, LLC.
42245 * Originally Released Under LGPL - original licence link has changed is not relivant.
42248 * <script type="text/javascript">
42251 * @class Roo.form.Checkbox
42252 * @extends Roo.form.Field
42253 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42255 * Creates a new Checkbox
42256 * @param {Object} config Configuration options
42258 Roo.form.Checkbox = function(config){
42259 Roo.form.Checkbox.superclass.constructor.call(this, config);
42263 * Fires when the checkbox is checked or unchecked.
42264 * @param {Roo.form.Checkbox} this This checkbox
42265 * @param {Boolean} checked The new checked value
42271 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42273 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42275 focusClass : undefined,
42277 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42279 fieldClass: "x-form-field",
42281 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42285 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42286 * {tag: "input", type: "checkbox", autocomplete: "off"})
42288 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42290 * @cfg {String} boxLabel The text that appears beside the checkbox
42294 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42298 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42300 valueOff: '0', // value when not checked..
42302 actionMode : 'viewEl',
42305 itemCls : 'x-menu-check-item x-form-item',
42306 groupClass : 'x-menu-group-item',
42307 inputType : 'hidden',
42310 inSetChecked: false, // check that we are not calling self...
42312 inputElement: false, // real input element?
42313 basedOn: false, // ????
42315 isFormField: true, // not sure where this is needed!!!!
42317 onResize : function(){
42318 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42319 if(!this.boxLabel){
42320 this.el.alignTo(this.wrap, 'c-c');
42324 initEvents : function(){
42325 Roo.form.Checkbox.superclass.initEvents.call(this);
42326 this.el.on("click", this.onClick, this);
42327 this.el.on("change", this.onClick, this);
42331 getResizeEl : function(){
42335 getPositionEl : function(){
42340 onRender : function(ct, position){
42341 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42343 if(this.inputValue !== undefined){
42344 this.el.dom.value = this.inputValue;
42347 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42348 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42349 var viewEl = this.wrap.createChild({
42350 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42351 this.viewEl = viewEl;
42352 this.wrap.on('click', this.onClick, this);
42354 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42355 this.el.on('propertychange', this.setFromHidden, this); //ie
42360 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42361 // viewEl.on('click', this.onClick, this);
42363 //if(this.checked){
42364 this.setChecked(this.checked);
42366 //this.checked = this.el.dom;
42372 initValue : Roo.emptyFn,
42375 * Returns the checked state of the checkbox.
42376 * @return {Boolean} True if checked, else false
42378 getValue : function(){
42380 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42382 return this.valueOff;
42387 onClick : function(){
42388 if (this.disabled) {
42391 this.setChecked(!this.checked);
42393 //if(this.el.dom.checked != this.checked){
42394 // this.setValue(this.el.dom.checked);
42399 * Sets the checked state of the checkbox.
42400 * On is always based on a string comparison between inputValue and the param.
42401 * @param {Boolean/String} value - the value to set
42402 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42404 setValue : function(v,suppressEvent){
42407 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42408 //if(this.el && this.el.dom){
42409 // this.el.dom.checked = this.checked;
42410 // this.el.dom.defaultChecked = this.checked;
42412 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42413 //this.fireEvent("check", this, this.checked);
42416 setChecked : function(state,suppressEvent)
42418 if (this.inSetChecked) {
42419 this.checked = state;
42425 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42427 this.checked = state;
42428 if(suppressEvent !== true){
42429 this.fireEvent('check', this, state);
42431 this.inSetChecked = true;
42432 this.el.dom.value = state ? this.inputValue : this.valueOff;
42433 this.inSetChecked = false;
42436 // handle setting of hidden value by some other method!!?!?
42437 setFromHidden: function()
42442 //console.log("SET FROM HIDDEN");
42443 //alert('setFrom hidden');
42444 this.setValue(this.el.dom.value);
42447 onDestroy : function()
42450 Roo.get(this.viewEl).remove();
42453 Roo.form.Checkbox.superclass.onDestroy.call(this);
42456 setBoxLabel : function(str)
42458 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42463 * Ext JS Library 1.1.1
42464 * Copyright(c) 2006-2007, Ext JS, LLC.
42466 * Originally Released Under LGPL - original licence link has changed is not relivant.
42469 * <script type="text/javascript">
42473 * @class Roo.form.Radio
42474 * @extends Roo.form.Checkbox
42475 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42476 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42478 * Creates a new Radio
42479 * @param {Object} config Configuration options
42481 Roo.form.Radio = function(){
42482 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42484 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42485 inputType: 'radio',
42488 * If this radio is part of a group, it will return the selected value
42491 getGroupValue : function(){
42492 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42496 onRender : function(ct, position){
42497 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42499 if(this.inputValue !== undefined){
42500 this.el.dom.value = this.inputValue;
42503 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42504 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42505 //var viewEl = this.wrap.createChild({
42506 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42507 //this.viewEl = viewEl;
42508 //this.wrap.on('click', this.onClick, this);
42510 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42511 //this.el.on('propertychange', this.setFromHidden, this); //ie
42516 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42517 // viewEl.on('click', this.onClick, this);
42520 this.el.dom.checked = 'checked' ;
42526 });//<script type="text/javascript">
42529 * Based Ext JS Library 1.1.1
42530 * Copyright(c) 2006-2007, Ext JS, LLC.
42536 * @class Roo.HtmlEditorCore
42537 * @extends Roo.Component
42538 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42540 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42543 Roo.HtmlEditorCore = function(config){
42546 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42551 * @event initialize
42552 * Fires when the editor is fully initialized (including the iframe)
42553 * @param {Roo.HtmlEditorCore} this
42558 * Fires when the editor is first receives the focus. Any insertion must wait
42559 * until after this event.
42560 * @param {Roo.HtmlEditorCore} this
42564 * @event beforesync
42565 * Fires before the textarea is updated with content from the editor iframe. Return false
42566 * to cancel the sync.
42567 * @param {Roo.HtmlEditorCore} this
42568 * @param {String} html
42572 * @event beforepush
42573 * Fires before the iframe editor is updated with content from the textarea. Return false
42574 * to cancel the push.
42575 * @param {Roo.HtmlEditorCore} this
42576 * @param {String} html
42581 * Fires when the textarea is updated with content from the editor iframe.
42582 * @param {Roo.HtmlEditorCore} this
42583 * @param {String} html
42588 * Fires when the iframe editor is updated with content from the textarea.
42589 * @param {Roo.HtmlEditorCore} this
42590 * @param {String} html
42595 * @event editorevent
42596 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42597 * @param {Roo.HtmlEditorCore} this
42603 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42605 // defaults : white / black...
42606 this.applyBlacklists();
42613 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42617 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42623 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42628 * @cfg {Number} height (in pixels)
42632 * @cfg {Number} width (in pixels)
42637 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42640 stylesheets: false,
42645 // private properties
42646 validationEvent : false,
42648 initialized : false,
42650 sourceEditMode : false,
42651 onFocus : Roo.emptyFn,
42653 hideMode:'offsets',
42657 // blacklist + whitelisted elements..
42664 * Protected method that will not generally be called directly. It
42665 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42666 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42668 getDocMarkup : function(){
42672 // inherit styels from page...??
42673 if (this.stylesheets === false) {
42675 Roo.get(document.head).select('style').each(function(node) {
42676 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42679 Roo.get(document.head).select('link').each(function(node) {
42680 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42683 } else if (!this.stylesheets.length) {
42685 st = '<style type="text/css">' +
42686 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42692 st += '<style type="text/css">' +
42693 'IMG { cursor: pointer } ' +
42697 return '<html><head>' + st +
42698 //<style type="text/css">' +
42699 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42701 ' </head><body class="roo-htmleditor-body"></body></html>';
42705 onRender : function(ct, position)
42708 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42709 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42712 this.el.dom.style.border = '0 none';
42713 this.el.dom.setAttribute('tabIndex', -1);
42714 this.el.addClass('x-hidden hide');
42718 if(Roo.isIE){ // fix IE 1px bogus margin
42719 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42723 this.frameId = Roo.id();
42727 var iframe = this.owner.wrap.createChild({
42729 cls: 'form-control', // bootstrap..
42731 name: this.frameId,
42732 frameBorder : 'no',
42733 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42738 this.iframe = iframe.dom;
42740 this.assignDocWin();
42742 this.doc.designMode = 'on';
42745 this.doc.write(this.getDocMarkup());
42749 var task = { // must defer to wait for browser to be ready
42751 //console.log("run task?" + this.doc.readyState);
42752 this.assignDocWin();
42753 if(this.doc.body || this.doc.readyState == 'complete'){
42755 this.doc.designMode="on";
42759 Roo.TaskMgr.stop(task);
42760 this.initEditor.defer(10, this);
42767 Roo.TaskMgr.start(task);
42772 onResize : function(w, h)
42774 Roo.log('resize: ' +w + ',' + h );
42775 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42779 if(typeof w == 'number'){
42781 this.iframe.style.width = w + 'px';
42783 if(typeof h == 'number'){
42785 this.iframe.style.height = h + 'px';
42787 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42794 * Toggles the editor between standard and source edit mode.
42795 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42797 toggleSourceEdit : function(sourceEditMode){
42799 this.sourceEditMode = sourceEditMode === true;
42801 if(this.sourceEditMode){
42803 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42806 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42807 //this.iframe.className = '';
42810 //this.setSize(this.owner.wrap.getSize());
42811 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42818 * Protected method that will not generally be called directly. If you need/want
42819 * custom HTML cleanup, this is the method you should override.
42820 * @param {String} html The HTML to be cleaned
42821 * return {String} The cleaned HTML
42823 cleanHtml : function(html){
42824 html = String(html);
42825 if(html.length > 5){
42826 if(Roo.isSafari){ // strip safari nonsense
42827 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42830 if(html == ' '){
42837 * HTML Editor -> Textarea
42838 * Protected method that will not generally be called directly. Syncs the contents
42839 * of the editor iframe with the textarea.
42841 syncValue : function(){
42842 if(this.initialized){
42843 var bd = (this.doc.body || this.doc.documentElement);
42844 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42845 var html = bd.innerHTML;
42847 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
42848 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
42850 html = '<div style="'+m[0]+'">' + html + '</div>';
42853 html = this.cleanHtml(html);
42854 // fix up the special chars.. normaly like back quotes in word...
42855 // however we do not want to do this with chinese..
42856 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
42857 var cc = b.charCodeAt();
42859 (cc >= 0x4E00 && cc < 0xA000 ) ||
42860 (cc >= 0x3400 && cc < 0x4E00 ) ||
42861 (cc >= 0xf900 && cc < 0xfb00 )
42867 if(this.owner.fireEvent('beforesync', this, html) !== false){
42868 this.el.dom.value = html;
42869 this.owner.fireEvent('sync', this, html);
42875 * Protected method that will not generally be called directly. Pushes the value of the textarea
42876 * into the iframe editor.
42878 pushValue : function(){
42879 if(this.initialized){
42880 var v = this.el.dom.value.trim();
42882 // if(v.length < 1){
42886 if(this.owner.fireEvent('beforepush', this, v) !== false){
42887 var d = (this.doc.body || this.doc.documentElement);
42889 this.cleanUpPaste();
42890 this.el.dom.value = d.innerHTML;
42891 this.owner.fireEvent('push', this, v);
42897 deferFocus : function(){
42898 this.focus.defer(10, this);
42902 focus : function(){
42903 if(this.win && !this.sourceEditMode){
42910 assignDocWin: function()
42912 var iframe = this.iframe;
42915 this.doc = iframe.contentWindow.document;
42916 this.win = iframe.contentWindow;
42918 // if (!Roo.get(this.frameId)) {
42921 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
42922 // this.win = Roo.get(this.frameId).dom.contentWindow;
42924 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
42928 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
42929 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
42934 initEditor : function(){
42935 //console.log("INIT EDITOR");
42936 this.assignDocWin();
42940 this.doc.designMode="on";
42942 this.doc.write(this.getDocMarkup());
42945 var dbody = (this.doc.body || this.doc.documentElement);
42946 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
42947 // this copies styles from the containing element into thsi one..
42948 // not sure why we need all of this..
42949 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
42951 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
42952 //ss['background-attachment'] = 'fixed'; // w3c
42953 dbody.bgProperties = 'fixed'; // ie
42954 //Roo.DomHelper.applyStyles(dbody, ss);
42955 Roo.EventManager.on(this.doc, {
42956 //'mousedown': this.onEditorEvent,
42957 'mouseup': this.onEditorEvent,
42958 'dblclick': this.onEditorEvent,
42959 'click': this.onEditorEvent,
42960 'keyup': this.onEditorEvent,
42965 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
42967 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
42968 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
42970 this.initialized = true;
42972 this.owner.fireEvent('initialize', this);
42977 onDestroy : function(){
42983 //for (var i =0; i < this.toolbars.length;i++) {
42984 // // fixme - ask toolbars for heights?
42985 // this.toolbars[i].onDestroy();
42988 //this.wrap.dom.innerHTML = '';
42989 //this.wrap.remove();
42994 onFirstFocus : function(){
42996 this.assignDocWin();
42999 this.activated = true;
43002 if(Roo.isGecko){ // prevent silly gecko errors
43004 var s = this.win.getSelection();
43005 if(!s.focusNode || s.focusNode.nodeType != 3){
43006 var r = s.getRangeAt(0);
43007 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43012 this.execCmd('useCSS', true);
43013 this.execCmd('styleWithCSS', false);
43016 this.owner.fireEvent('activate', this);
43020 adjustFont: function(btn){
43021 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43022 //if(Roo.isSafari){ // safari
43025 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43026 if(Roo.isSafari){ // safari
43027 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43028 v = (v < 10) ? 10 : v;
43029 v = (v > 48) ? 48 : v;
43030 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43035 v = Math.max(1, v+adjust);
43037 this.execCmd('FontSize', v );
43040 onEditorEvent : function(e)
43042 this.owner.fireEvent('editorevent', this, e);
43043 // this.updateToolbar();
43044 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43047 insertTag : function(tg)
43049 // could be a bit smarter... -> wrap the current selected tRoo..
43050 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43052 range = this.createRange(this.getSelection());
43053 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43054 wrappingNode.appendChild(range.extractContents());
43055 range.insertNode(wrappingNode);
43062 this.execCmd("formatblock", tg);
43066 insertText : function(txt)
43070 var range = this.createRange();
43071 range.deleteContents();
43072 //alert(Sender.getAttribute('label'));
43074 range.insertNode(this.doc.createTextNode(txt));
43080 * Executes a Midas editor command on the editor document and performs necessary focus and
43081 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43082 * @param {String} cmd The Midas command
43083 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43085 relayCmd : function(cmd, value){
43087 this.execCmd(cmd, value);
43088 this.owner.fireEvent('editorevent', this);
43089 //this.updateToolbar();
43090 this.owner.deferFocus();
43094 * Executes a Midas editor command directly on the editor document.
43095 * For visual commands, you should use {@link #relayCmd} instead.
43096 * <b>This should only be called after the editor is initialized.</b>
43097 * @param {String} cmd The Midas command
43098 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43100 execCmd : function(cmd, value){
43101 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43108 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43110 * @param {String} text | dom node..
43112 insertAtCursor : function(text)
43117 if(!this.activated){
43123 var r = this.doc.selection.createRange();
43134 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43138 // from jquery ui (MIT licenced)
43140 var win = this.win;
43142 if (win.getSelection && win.getSelection().getRangeAt) {
43143 range = win.getSelection().getRangeAt(0);
43144 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43145 range.insertNode(node);
43146 } else if (win.document.selection && win.document.selection.createRange) {
43147 // no firefox support
43148 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43149 win.document.selection.createRange().pasteHTML(txt);
43151 // no firefox support
43152 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43153 this.execCmd('InsertHTML', txt);
43162 mozKeyPress : function(e){
43164 var c = e.getCharCode(), cmd;
43167 c = String.fromCharCode(c).toLowerCase();
43181 this.cleanUpPaste.defer(100, this);
43189 e.preventDefault();
43197 fixKeys : function(){ // load time branching for fastest keydown performance
43199 return function(e){
43200 var k = e.getKey(), r;
43203 r = this.doc.selection.createRange();
43206 r.pasteHTML('    ');
43213 r = this.doc.selection.createRange();
43215 var target = r.parentElement();
43216 if(!target || target.tagName.toLowerCase() != 'li'){
43218 r.pasteHTML('<br />');
43224 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43225 this.cleanUpPaste.defer(100, this);
43231 }else if(Roo.isOpera){
43232 return function(e){
43233 var k = e.getKey();
43237 this.execCmd('InsertHTML','    ');
43240 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43241 this.cleanUpPaste.defer(100, this);
43246 }else if(Roo.isSafari){
43247 return function(e){
43248 var k = e.getKey();
43252 this.execCmd('InsertText','\t');
43256 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43257 this.cleanUpPaste.defer(100, this);
43265 getAllAncestors: function()
43267 var p = this.getSelectedNode();
43270 a.push(p); // push blank onto stack..
43271 p = this.getParentElement();
43275 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43279 a.push(this.doc.body);
43283 lastSelNode : false,
43286 getSelection : function()
43288 this.assignDocWin();
43289 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43292 getSelectedNode: function()
43294 // this may only work on Gecko!!!
43296 // should we cache this!!!!
43301 var range = this.createRange(this.getSelection()).cloneRange();
43304 var parent = range.parentElement();
43306 var testRange = range.duplicate();
43307 testRange.moveToElementText(parent);
43308 if (testRange.inRange(range)) {
43311 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43314 parent = parent.parentElement;
43319 // is ancestor a text element.
43320 var ac = range.commonAncestorContainer;
43321 if (ac.nodeType == 3) {
43322 ac = ac.parentNode;
43325 var ar = ac.childNodes;
43328 var other_nodes = [];
43329 var has_other_nodes = false;
43330 for (var i=0;i<ar.length;i++) {
43331 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43334 // fullly contained node.
43336 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43341 // probably selected..
43342 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43343 other_nodes.push(ar[i]);
43347 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43352 has_other_nodes = true;
43354 if (!nodes.length && other_nodes.length) {
43355 nodes= other_nodes;
43357 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43363 createRange: function(sel)
43365 // this has strange effects when using with
43366 // top toolbar - not sure if it's a great idea.
43367 //this.editor.contentWindow.focus();
43368 if (typeof sel != "undefined") {
43370 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43372 return this.doc.createRange();
43375 return this.doc.createRange();
43378 getParentElement: function()
43381 this.assignDocWin();
43382 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43384 var range = this.createRange(sel);
43387 var p = range.commonAncestorContainer;
43388 while (p.nodeType == 3) { // text node
43399 * Range intersection.. the hard stuff...
43403 * [ -- selected range --- ]
43407 * if end is before start or hits it. fail.
43408 * if start is after end or hits it fail.
43410 * if either hits (but other is outside. - then it's not
43416 // @see http://www.thismuchiknow.co.uk/?p=64.
43417 rangeIntersectsNode : function(range, node)
43419 var nodeRange = node.ownerDocument.createRange();
43421 nodeRange.selectNode(node);
43423 nodeRange.selectNodeContents(node);
43426 var rangeStartRange = range.cloneRange();
43427 rangeStartRange.collapse(true);
43429 var rangeEndRange = range.cloneRange();
43430 rangeEndRange.collapse(false);
43432 var nodeStartRange = nodeRange.cloneRange();
43433 nodeStartRange.collapse(true);
43435 var nodeEndRange = nodeRange.cloneRange();
43436 nodeEndRange.collapse(false);
43438 return rangeStartRange.compareBoundaryPoints(
43439 Range.START_TO_START, nodeEndRange) == -1 &&
43440 rangeEndRange.compareBoundaryPoints(
43441 Range.START_TO_START, nodeStartRange) == 1;
43445 rangeCompareNode : function(range, node)
43447 var nodeRange = node.ownerDocument.createRange();
43449 nodeRange.selectNode(node);
43451 nodeRange.selectNodeContents(node);
43455 range.collapse(true);
43457 nodeRange.collapse(true);
43459 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43460 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43462 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43464 var nodeIsBefore = ss == 1;
43465 var nodeIsAfter = ee == -1;
43467 if (nodeIsBefore && nodeIsAfter) {
43470 if (!nodeIsBefore && nodeIsAfter) {
43471 return 1; //right trailed.
43474 if (nodeIsBefore && !nodeIsAfter) {
43475 return 2; // left trailed.
43481 // private? - in a new class?
43482 cleanUpPaste : function()
43484 // cleans up the whole document..
43485 Roo.log('cleanuppaste');
43487 this.cleanUpChildren(this.doc.body);
43488 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43489 if (clean != this.doc.body.innerHTML) {
43490 this.doc.body.innerHTML = clean;
43495 cleanWordChars : function(input) {// change the chars to hex code
43496 var he = Roo.HtmlEditorCore;
43498 var output = input;
43499 Roo.each(he.swapCodes, function(sw) {
43500 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43502 output = output.replace(swapper, sw[1]);
43509 cleanUpChildren : function (n)
43511 if (!n.childNodes.length) {
43514 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43515 this.cleanUpChild(n.childNodes[i]);
43522 cleanUpChild : function (node)
43525 //console.log(node);
43526 if (node.nodeName == "#text") {
43527 // clean up silly Windows -- stuff?
43530 if (node.nodeName == "#comment") {
43531 node.parentNode.removeChild(node);
43532 // clean up silly Windows -- stuff?
43535 var lcname = node.tagName.toLowerCase();
43536 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43537 // whitelist of tags..
43539 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43541 node.parentNode.removeChild(node);
43546 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43548 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43549 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43551 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43552 // remove_keep_children = true;
43555 if (remove_keep_children) {
43556 this.cleanUpChildren(node);
43557 // inserts everything just before this node...
43558 while (node.childNodes.length) {
43559 var cn = node.childNodes[0];
43560 node.removeChild(cn);
43561 node.parentNode.insertBefore(cn, node);
43563 node.parentNode.removeChild(node);
43567 if (!node.attributes || !node.attributes.length) {
43568 this.cleanUpChildren(node);
43572 function cleanAttr(n,v)
43575 if (v.match(/^\./) || v.match(/^\//)) {
43578 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43581 if (v.match(/^#/)) {
43584 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43585 node.removeAttribute(n);
43589 var cwhite = this.cwhite;
43590 var cblack = this.cblack;
43592 function cleanStyle(n,v)
43594 if (v.match(/expression/)) { //XSS?? should we even bother..
43595 node.removeAttribute(n);
43599 var parts = v.split(/;/);
43602 Roo.each(parts, function(p) {
43603 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43607 var l = p.split(':').shift().replace(/\s+/g,'');
43608 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43610 if ( cwhite.length && cblack.indexOf(l) > -1) {
43611 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43612 //node.removeAttribute(n);
43616 // only allow 'c whitelisted system attributes'
43617 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43618 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43619 //node.removeAttribute(n);
43629 if (clean.length) {
43630 node.setAttribute(n, clean.join(';'));
43632 node.removeAttribute(n);
43638 for (var i = node.attributes.length-1; i > -1 ; i--) {
43639 var a = node.attributes[i];
43642 if (a.name.toLowerCase().substr(0,2)=='on') {
43643 node.removeAttribute(a.name);
43646 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43647 node.removeAttribute(a.name);
43650 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43651 cleanAttr(a.name,a.value); // fixme..
43654 if (a.name == 'style') {
43655 cleanStyle(a.name,a.value);
43658 /// clean up MS crap..
43659 // tecnically this should be a list of valid class'es..
43662 if (a.name == 'class') {
43663 if (a.value.match(/^Mso/)) {
43664 node.className = '';
43667 if (a.value.match(/body/)) {
43668 node.className = '';
43679 this.cleanUpChildren(node);
43685 * Clean up MS wordisms...
43687 cleanWord : function(node)
43692 this.cleanWord(this.doc.body);
43695 if (node.nodeName == "#text") {
43696 // clean up silly Windows -- stuff?
43699 if (node.nodeName == "#comment") {
43700 node.parentNode.removeChild(node);
43701 // clean up silly Windows -- stuff?
43705 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43706 node.parentNode.removeChild(node);
43710 // remove - but keep children..
43711 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43712 while (node.childNodes.length) {
43713 var cn = node.childNodes[0];
43714 node.removeChild(cn);
43715 node.parentNode.insertBefore(cn, node);
43717 node.parentNode.removeChild(node);
43718 this.iterateChildren(node, this.cleanWord);
43722 if (node.className.length) {
43724 var cn = node.className.split(/\W+/);
43726 Roo.each(cn, function(cls) {
43727 if (cls.match(/Mso[a-zA-Z]+/)) {
43732 node.className = cna.length ? cna.join(' ') : '';
43734 node.removeAttribute("class");
43738 if (node.hasAttribute("lang")) {
43739 node.removeAttribute("lang");
43742 if (node.hasAttribute("style")) {
43744 var styles = node.getAttribute("style").split(";");
43746 Roo.each(styles, function(s) {
43747 if (!s.match(/:/)) {
43750 var kv = s.split(":");
43751 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43754 // what ever is left... we allow.
43757 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43758 if (!nstyle.length) {
43759 node.removeAttribute('style');
43762 this.iterateChildren(node, this.cleanWord);
43768 * iterateChildren of a Node, calling fn each time, using this as the scole..
43769 * @param {DomNode} node node to iterate children of.
43770 * @param {Function} fn method of this class to call on each item.
43772 iterateChildren : function(node, fn)
43774 if (!node.childNodes.length) {
43777 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43778 fn.call(this, node.childNodes[i])
43784 * cleanTableWidths.
43786 * Quite often pasting from word etc.. results in tables with column and widths.
43787 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43790 cleanTableWidths : function(node)
43795 this.cleanTableWidths(this.doc.body);
43800 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43803 Roo.log(node.tagName);
43804 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43805 this.iterateChildren(node, this.cleanTableWidths);
43808 if (node.hasAttribute('width')) {
43809 node.removeAttribute('width');
43813 if (node.hasAttribute("style")) {
43816 var styles = node.getAttribute("style").split(";");
43818 Roo.each(styles, function(s) {
43819 if (!s.match(/:/)) {
43822 var kv = s.split(":");
43823 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43826 // what ever is left... we allow.
43829 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43830 if (!nstyle.length) {
43831 node.removeAttribute('style');
43835 this.iterateChildren(node, this.cleanTableWidths);
43843 domToHTML : function(currentElement, depth, nopadtext) {
43845 depth = depth || 0;
43846 nopadtext = nopadtext || false;
43848 if (!currentElement) {
43849 return this.domToHTML(this.doc.body);
43852 //Roo.log(currentElement);
43854 var allText = false;
43855 var nodeName = currentElement.nodeName;
43856 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
43858 if (nodeName == '#text') {
43860 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
43865 if (nodeName != 'BODY') {
43868 // Prints the node tagName, such as <A>, <IMG>, etc
43871 for(i = 0; i < currentElement.attributes.length;i++) {
43873 var aname = currentElement.attributes.item(i).name;
43874 if (!currentElement.attributes.item(i).value.length) {
43877 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
43880 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
43889 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
43892 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
43897 // Traverse the tree
43899 var currentElementChild = currentElement.childNodes.item(i);
43900 var allText = true;
43901 var innerHTML = '';
43903 while (currentElementChild) {
43904 // Formatting code (indent the tree so it looks nice on the screen)
43905 var nopad = nopadtext;
43906 if (lastnode == 'SPAN') {
43910 if (currentElementChild.nodeName == '#text') {
43911 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
43912 toadd = nopadtext ? toadd : toadd.trim();
43913 if (!nopad && toadd.length > 80) {
43914 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
43916 innerHTML += toadd;
43919 currentElementChild = currentElement.childNodes.item(i);
43925 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
43927 // Recursively traverse the tree structure of the child node
43928 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
43929 lastnode = currentElementChild.nodeName;
43931 currentElementChild=currentElement.childNodes.item(i);
43937 // The remaining code is mostly for formatting the tree
43938 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
43943 ret+= "</"+tagName+">";
43949 applyBlacklists : function()
43951 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
43952 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
43956 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
43957 if (b.indexOf(tag) > -1) {
43960 this.white.push(tag);
43964 Roo.each(w, function(tag) {
43965 if (b.indexOf(tag) > -1) {
43968 if (this.white.indexOf(tag) > -1) {
43971 this.white.push(tag);
43976 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
43977 if (w.indexOf(tag) > -1) {
43980 this.black.push(tag);
43984 Roo.each(b, function(tag) {
43985 if (w.indexOf(tag) > -1) {
43988 if (this.black.indexOf(tag) > -1) {
43991 this.black.push(tag);
43996 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
43997 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44001 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44002 if (b.indexOf(tag) > -1) {
44005 this.cwhite.push(tag);
44009 Roo.each(w, function(tag) {
44010 if (b.indexOf(tag) > -1) {
44013 if (this.cwhite.indexOf(tag) > -1) {
44016 this.cwhite.push(tag);
44021 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44022 if (w.indexOf(tag) > -1) {
44025 this.cblack.push(tag);
44029 Roo.each(b, function(tag) {
44030 if (w.indexOf(tag) > -1) {
44033 if (this.cblack.indexOf(tag) > -1) {
44036 this.cblack.push(tag);
44041 setStylesheets : function(stylesheets)
44043 if(typeof(stylesheets) == 'string'){
44044 Roo.get(this.iframe.contentDocument.head).createChild({
44046 rel : 'stylesheet',
44055 Roo.each(stylesheets, function(s) {
44060 Roo.get(_this.iframe.contentDocument.head).createChild({
44062 rel : 'stylesheet',
44071 removeStylesheets : function()
44075 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44080 // hide stuff that is not compatible
44094 * @event specialkey
44098 * @cfg {String} fieldClass @hide
44101 * @cfg {String} focusClass @hide
44104 * @cfg {String} autoCreate @hide
44107 * @cfg {String} inputType @hide
44110 * @cfg {String} invalidClass @hide
44113 * @cfg {String} invalidText @hide
44116 * @cfg {String} msgFx @hide
44119 * @cfg {String} validateOnBlur @hide
44123 Roo.HtmlEditorCore.white = [
44124 'area', 'br', 'img', 'input', 'hr', 'wbr',
44126 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44127 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44128 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44129 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44130 'table', 'ul', 'xmp',
44132 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44135 'dir', 'menu', 'ol', 'ul', 'dl',
44141 Roo.HtmlEditorCore.black = [
44142 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44144 'base', 'basefont', 'bgsound', 'blink', 'body',
44145 'frame', 'frameset', 'head', 'html', 'ilayer',
44146 'iframe', 'layer', 'link', 'meta', 'object',
44147 'script', 'style' ,'title', 'xml' // clean later..
44149 Roo.HtmlEditorCore.clean = [
44150 'script', 'style', 'title', 'xml'
44152 Roo.HtmlEditorCore.remove = [
44157 Roo.HtmlEditorCore.ablack = [
44161 Roo.HtmlEditorCore.aclean = [
44162 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44166 Roo.HtmlEditorCore.pwhite= [
44167 'http', 'https', 'mailto'
44170 // white listed style attributes.
44171 Roo.HtmlEditorCore.cwhite= [
44172 // 'text-align', /// default is to allow most things..
44178 // black listed style attributes.
44179 Roo.HtmlEditorCore.cblack= [
44180 // 'font-size' -- this can be set by the project
44184 Roo.HtmlEditorCore.swapCodes =[
44195 //<script type="text/javascript">
44198 * Ext JS Library 1.1.1
44199 * Copyright(c) 2006-2007, Ext JS, LLC.
44205 Roo.form.HtmlEditor = function(config){
44209 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44211 if (!this.toolbars) {
44212 this.toolbars = [];
44214 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44220 * @class Roo.form.HtmlEditor
44221 * @extends Roo.form.Field
44222 * Provides a lightweight HTML Editor component.
44224 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44226 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44227 * supported by this editor.</b><br/><br/>
44228 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44229 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44231 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44233 * @cfg {Boolean} clearUp
44237 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44242 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44247 * @cfg {Number} height (in pixels)
44251 * @cfg {Number} width (in pixels)
44256 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44259 stylesheets: false,
44263 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44268 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44274 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44279 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44287 // private properties
44288 validationEvent : false,
44290 initialized : false,
44293 onFocus : Roo.emptyFn,
44295 hideMode:'offsets',
44297 actionMode : 'container', // defaults to hiding it...
44299 defaultAutoCreate : { // modified by initCompnoent..
44301 style:"width:500px;height:300px;",
44302 autocomplete: "new-password"
44306 initComponent : function(){
44309 * @event initialize
44310 * Fires when the editor is fully initialized (including the iframe)
44311 * @param {HtmlEditor} this
44316 * Fires when the editor is first receives the focus. Any insertion must wait
44317 * until after this event.
44318 * @param {HtmlEditor} this
44322 * @event beforesync
44323 * Fires before the textarea is updated with content from the editor iframe. Return false
44324 * to cancel the sync.
44325 * @param {HtmlEditor} this
44326 * @param {String} html
44330 * @event beforepush
44331 * Fires before the iframe editor is updated with content from the textarea. Return false
44332 * to cancel the push.
44333 * @param {HtmlEditor} this
44334 * @param {String} html
44339 * Fires when the textarea is updated with content from the editor iframe.
44340 * @param {HtmlEditor} this
44341 * @param {String} html
44346 * Fires when the iframe editor is updated with content from the textarea.
44347 * @param {HtmlEditor} this
44348 * @param {String} html
44352 * @event editmodechange
44353 * Fires when the editor switches edit modes
44354 * @param {HtmlEditor} this
44355 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44357 editmodechange: true,
44359 * @event editorevent
44360 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44361 * @param {HtmlEditor} this
44365 * @event firstfocus
44366 * Fires when on first focus - needed by toolbars..
44367 * @param {HtmlEditor} this
44372 * Auto save the htmlEditor value as a file into Events
44373 * @param {HtmlEditor} this
44377 * @event savedpreview
44378 * preview the saved version of htmlEditor
44379 * @param {HtmlEditor} this
44381 savedpreview: true,
44384 * @event stylesheetsclick
44385 * Fires when press the Sytlesheets button
44386 * @param {Roo.HtmlEditorCore} this
44388 stylesheetsclick: true
44390 this.defaultAutoCreate = {
44392 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44393 autocomplete: "new-password"
44398 * Protected method that will not generally be called directly. It
44399 * is called when the editor creates its toolbar. Override this method if you need to
44400 * add custom toolbar buttons.
44401 * @param {HtmlEditor} editor
44403 createToolbar : function(editor){
44404 Roo.log("create toolbars");
44405 if (!editor.toolbars || !editor.toolbars.length) {
44406 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44409 for (var i =0 ; i < editor.toolbars.length;i++) {
44410 editor.toolbars[i] = Roo.factory(
44411 typeof(editor.toolbars[i]) == 'string' ?
44412 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44413 Roo.form.HtmlEditor);
44414 editor.toolbars[i].init(editor);
44422 onRender : function(ct, position)
44425 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44427 this.wrap = this.el.wrap({
44428 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44431 this.editorcore.onRender(ct, position);
44433 if (this.resizable) {
44434 this.resizeEl = new Roo.Resizable(this.wrap, {
44438 minHeight : this.height,
44439 height: this.height,
44440 handles : this.resizable,
44443 resize : function(r, w, h) {
44444 _t.onResize(w,h); // -something
44450 this.createToolbar(this);
44454 this.setSize(this.wrap.getSize());
44456 if (this.resizeEl) {
44457 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44458 // should trigger onReize..
44461 this.keyNav = new Roo.KeyNav(this.el, {
44463 "tab" : function(e){
44464 e.preventDefault();
44466 var value = this.getValue();
44468 var start = this.el.dom.selectionStart;
44469 var end = this.el.dom.selectionEnd;
44473 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44474 this.el.dom.setSelectionRange(end + 1, end + 1);
44478 var f = value.substring(0, start).split("\t");
44480 if(f.pop().length != 0){
44484 this.setValue(f.join("\t") + value.substring(end));
44485 this.el.dom.setSelectionRange(start - 1, start - 1);
44489 "home" : function(e){
44490 e.preventDefault();
44492 var curr = this.el.dom.selectionStart;
44493 var lines = this.getValue().split("\n");
44500 this.el.dom.setSelectionRange(0, 0);
44506 for (var i = 0; i < lines.length;i++) {
44507 pos += lines[i].length;
44517 pos -= lines[i].length;
44523 this.el.dom.setSelectionRange(pos, pos);
44527 this.el.dom.selectionStart = pos;
44528 this.el.dom.selectionEnd = curr;
44531 "end" : function(e){
44532 e.preventDefault();
44534 var curr = this.el.dom.selectionStart;
44535 var lines = this.getValue().split("\n");
44542 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44548 for (var i = 0; i < lines.length;i++) {
44550 pos += lines[i].length;
44564 this.el.dom.setSelectionRange(pos, pos);
44568 this.el.dom.selectionStart = curr;
44569 this.el.dom.selectionEnd = pos;
44574 doRelay : function(foo, bar, hname){
44575 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44581 // if(this.autosave && this.w){
44582 // this.autoSaveFn = setInterval(this.autosave, 1000);
44587 onResize : function(w, h)
44589 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44594 if(typeof w == 'number'){
44595 var aw = w - this.wrap.getFrameWidth('lr');
44596 this.el.setWidth(this.adjustWidth('textarea', aw));
44599 if(typeof h == 'number'){
44601 for (var i =0; i < this.toolbars.length;i++) {
44602 // fixme - ask toolbars for heights?
44603 tbh += this.toolbars[i].tb.el.getHeight();
44604 if (this.toolbars[i].footer) {
44605 tbh += this.toolbars[i].footer.el.getHeight();
44612 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44613 ah -= 5; // knock a few pixes off for look..
44615 this.el.setHeight(this.adjustWidth('textarea', ah));
44619 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44620 this.editorcore.onResize(ew,eh);
44625 * Toggles the editor between standard and source edit mode.
44626 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44628 toggleSourceEdit : function(sourceEditMode)
44630 this.editorcore.toggleSourceEdit(sourceEditMode);
44632 if(this.editorcore.sourceEditMode){
44633 Roo.log('editor - showing textarea');
44636 // Roo.log(this.syncValue());
44637 this.editorcore.syncValue();
44638 this.el.removeClass('x-hidden');
44639 this.el.dom.removeAttribute('tabIndex');
44642 for (var i = 0; i < this.toolbars.length; i++) {
44643 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44644 this.toolbars[i].tb.hide();
44645 this.toolbars[i].footer.hide();
44650 Roo.log('editor - hiding textarea');
44652 // Roo.log(this.pushValue());
44653 this.editorcore.pushValue();
44655 this.el.addClass('x-hidden');
44656 this.el.dom.setAttribute('tabIndex', -1);
44658 for (var i = 0; i < this.toolbars.length; i++) {
44659 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44660 this.toolbars[i].tb.show();
44661 this.toolbars[i].footer.show();
44665 //this.deferFocus();
44668 this.setSize(this.wrap.getSize());
44669 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44671 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44674 // private (for BoxComponent)
44675 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44677 // private (for BoxComponent)
44678 getResizeEl : function(){
44682 // private (for BoxComponent)
44683 getPositionEl : function(){
44688 initEvents : function(){
44689 this.originalValue = this.getValue();
44693 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44696 markInvalid : Roo.emptyFn,
44698 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44701 clearInvalid : Roo.emptyFn,
44703 setValue : function(v){
44704 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44705 this.editorcore.pushValue();
44710 deferFocus : function(){
44711 this.focus.defer(10, this);
44715 focus : function(){
44716 this.editorcore.focus();
44722 onDestroy : function(){
44728 for (var i =0; i < this.toolbars.length;i++) {
44729 // fixme - ask toolbars for heights?
44730 this.toolbars[i].onDestroy();
44733 this.wrap.dom.innerHTML = '';
44734 this.wrap.remove();
44739 onFirstFocus : function(){
44740 //Roo.log("onFirstFocus");
44741 this.editorcore.onFirstFocus();
44742 for (var i =0; i < this.toolbars.length;i++) {
44743 this.toolbars[i].onFirstFocus();
44749 syncValue : function()
44751 this.editorcore.syncValue();
44754 pushValue : function()
44756 this.editorcore.pushValue();
44759 setStylesheets : function(stylesheets)
44761 this.editorcore.setStylesheets(stylesheets);
44764 removeStylesheets : function()
44766 this.editorcore.removeStylesheets();
44770 // hide stuff that is not compatible
44784 * @event specialkey
44788 * @cfg {String} fieldClass @hide
44791 * @cfg {String} focusClass @hide
44794 * @cfg {String} autoCreate @hide
44797 * @cfg {String} inputType @hide
44800 * @cfg {String} invalidClass @hide
44803 * @cfg {String} invalidText @hide
44806 * @cfg {String} msgFx @hide
44809 * @cfg {String} validateOnBlur @hide
44813 // <script type="text/javascript">
44816 * Ext JS Library 1.1.1
44817 * Copyright(c) 2006-2007, Ext JS, LLC.
44823 * @class Roo.form.HtmlEditorToolbar1
44828 new Roo.form.HtmlEditor({
44831 new Roo.form.HtmlEditorToolbar1({
44832 disable : { fonts: 1 , format: 1, ..., ... , ...],
44838 * @cfg {Object} disable List of elements to disable..
44839 * @cfg {Array} btns List of additional buttons.
44843 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44846 Roo.form.HtmlEditor.ToolbarStandard = function(config)
44849 Roo.apply(this, config);
44851 // default disabled, based on 'good practice'..
44852 this.disable = this.disable || {};
44853 Roo.applyIf(this.disable, {
44856 specialElements : true
44860 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44861 // dont call parent... till later.
44864 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
44871 editorcore : false,
44873 * @cfg {Object} disable List of toolbar elements to disable
44880 * @cfg {String} createLinkText The default text for the create link prompt
44882 createLinkText : 'Please enter the URL for the link:',
44884 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
44886 defaultLinkValue : 'http:/'+'/',
44890 * @cfg {Array} fontFamilies An array of available font families
44908 // "á" , ?? a acute?
44913 "°" // , // degrees
44915 // "é" , // e ecute
44916 // "ú" , // u ecute?
44919 specialElements : [
44921 text: "Insert Table",
44924 ihtml : '<table><tr><td>Cell</td></tr></table>'
44928 text: "Insert Image",
44931 ihtml : '<img src="about:blank"/>'
44940 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
44941 "input:submit", "input:button", "select", "textarea", "label" ],
44944 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
44946 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
44954 * @cfg {String} defaultFont default font to use.
44956 defaultFont: 'tahoma',
44958 fontSelect : false,
44961 formatCombo : false,
44963 init : function(editor)
44965 this.editor = editor;
44966 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44967 var editorcore = this.editorcore;
44971 var fid = editorcore.frameId;
44973 function btn(id, toggle, handler){
44974 var xid = fid + '-'+ id ;
44978 cls : 'x-btn-icon x-edit-'+id,
44979 enableToggle:toggle !== false,
44980 scope: _t, // was editor...
44981 handler:handler||_t.relayBtnCmd,
44982 clickEvent:'mousedown',
44983 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44990 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
44992 // stop form submits
44993 tb.el.on('click', function(e){
44994 e.preventDefault(); // what does this do?
44997 if(!this.disable.font) { // && !Roo.isSafari){
44998 /* why no safari for fonts
44999 editor.fontSelect = tb.el.createChild({
45002 cls:'x-font-select',
45003 html: this.createFontOptions()
45006 editor.fontSelect.on('change', function(){
45007 var font = editor.fontSelect.dom.value;
45008 editor.relayCmd('fontname', font);
45009 editor.deferFocus();
45013 editor.fontSelect.dom,
45019 if(!this.disable.formats){
45020 this.formatCombo = new Roo.form.ComboBox({
45021 store: new Roo.data.SimpleStore({
45024 data : this.formats // from states.js
45028 //autoCreate : {tag: "div", size: "20"},
45029 displayField:'tag',
45033 triggerAction: 'all',
45034 emptyText:'Add tag',
45035 selectOnFocus:true,
45038 'select': function(c, r, i) {
45039 editorcore.insertTag(r.get('tag'));
45045 tb.addField(this.formatCombo);
45049 if(!this.disable.format){
45054 btn('strikethrough')
45057 if(!this.disable.fontSize){
45062 btn('increasefontsize', false, editorcore.adjustFont),
45063 btn('decreasefontsize', false, editorcore.adjustFont)
45068 if(!this.disable.colors){
45071 id:editorcore.frameId +'-forecolor',
45072 cls:'x-btn-icon x-edit-forecolor',
45073 clickEvent:'mousedown',
45074 tooltip: this.buttonTips['forecolor'] || undefined,
45076 menu : new Roo.menu.ColorMenu({
45077 allowReselect: true,
45078 focus: Roo.emptyFn,
45081 selectHandler: function(cp, color){
45082 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45083 editor.deferFocus();
45086 clickEvent:'mousedown'
45089 id:editorcore.frameId +'backcolor',
45090 cls:'x-btn-icon x-edit-backcolor',
45091 clickEvent:'mousedown',
45092 tooltip: this.buttonTips['backcolor'] || undefined,
45094 menu : new Roo.menu.ColorMenu({
45095 focus: Roo.emptyFn,
45098 allowReselect: true,
45099 selectHandler: function(cp, color){
45101 editorcore.execCmd('useCSS', false);
45102 editorcore.execCmd('hilitecolor', color);
45103 editorcore.execCmd('useCSS', true);
45104 editor.deferFocus();
45106 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45107 Roo.isSafari || Roo.isIE ? '#'+color : color);
45108 editor.deferFocus();
45112 clickEvent:'mousedown'
45117 // now add all the items...
45120 if(!this.disable.alignments){
45123 btn('justifyleft'),
45124 btn('justifycenter'),
45125 btn('justifyright')
45129 //if(!Roo.isSafari){
45130 if(!this.disable.links){
45133 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45137 if(!this.disable.lists){
45140 btn('insertorderedlist'),
45141 btn('insertunorderedlist')
45144 if(!this.disable.sourceEdit){
45147 btn('sourceedit', true, function(btn){
45148 this.toggleSourceEdit(btn.pressed);
45155 // special menu.. - needs to be tidied up..
45156 if (!this.disable.special) {
45159 cls: 'x-edit-none',
45165 for (var i =0; i < this.specialChars.length; i++) {
45166 smenu.menu.items.push({
45168 html: this.specialChars[i],
45169 handler: function(a,b) {
45170 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45171 //editor.insertAtCursor(a.html);
45185 if (!this.disable.cleanStyles) {
45187 cls: 'x-btn-icon x-btn-clear',
45193 for (var i =0; i < this.cleanStyles.length; i++) {
45194 cmenu.menu.items.push({
45195 actiontype : this.cleanStyles[i],
45196 html: 'Remove ' + this.cleanStyles[i],
45197 handler: function(a,b) {
45200 var c = Roo.get(editorcore.doc.body);
45201 c.select('[style]').each(function(s) {
45202 s.dom.style.removeProperty(a.actiontype);
45204 editorcore.syncValue();
45209 cmenu.menu.items.push({
45210 actiontype : 'tablewidths',
45211 html: 'Remove Table Widths',
45212 handler: function(a,b) {
45213 editorcore.cleanTableWidths();
45214 editorcore.syncValue();
45218 cmenu.menu.items.push({
45219 actiontype : 'word',
45220 html: 'Remove MS Word Formating',
45221 handler: function(a,b) {
45222 editorcore.cleanWord();
45223 editorcore.syncValue();
45228 cmenu.menu.items.push({
45229 actiontype : 'all',
45230 html: 'Remove All Styles',
45231 handler: function(a,b) {
45233 var c = Roo.get(editorcore.doc.body);
45234 c.select('[style]').each(function(s) {
45235 s.dom.removeAttribute('style');
45237 editorcore.syncValue();
45242 cmenu.menu.items.push({
45243 actiontype : 'all',
45244 html: 'Remove All CSS Classes',
45245 handler: function(a,b) {
45247 var c = Roo.get(editorcore.doc.body);
45248 c.select('[class]').each(function(s) {
45249 s.dom.className = '';
45251 editorcore.syncValue();
45256 cmenu.menu.items.push({
45257 actiontype : 'tidy',
45258 html: 'Tidy HTML Source',
45259 handler: function(a,b) {
45260 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45261 editorcore.syncValue();
45270 if (!this.disable.specialElements) {
45273 cls: 'x-edit-none',
45278 for (var i =0; i < this.specialElements.length; i++) {
45279 semenu.menu.items.push(
45281 handler: function(a,b) {
45282 editor.insertAtCursor(this.ihtml);
45284 }, this.specialElements[i])
45296 for(var i =0; i< this.btns.length;i++) {
45297 var b = Roo.factory(this.btns[i],Roo.form);
45298 b.cls = 'x-edit-none';
45300 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45301 b.cls += ' x-init-enable';
45304 b.scope = editorcore;
45312 // disable everything...
45314 this.tb.items.each(function(item){
45317 item.id != editorcore.frameId+ '-sourceedit' &&
45318 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45324 this.rendered = true;
45326 // the all the btns;
45327 editor.on('editorevent', this.updateToolbar, this);
45328 // other toolbars need to implement this..
45329 //editor.on('editmodechange', this.updateToolbar, this);
45333 relayBtnCmd : function(btn) {
45334 this.editorcore.relayCmd(btn.cmd);
45336 // private used internally
45337 createLink : function(){
45338 Roo.log("create link?");
45339 var url = prompt(this.createLinkText, this.defaultLinkValue);
45340 if(url && url != 'http:/'+'/'){
45341 this.editorcore.relayCmd('createlink', url);
45347 * Protected method that will not generally be called directly. It triggers
45348 * a toolbar update by reading the markup state of the current selection in the editor.
45350 updateToolbar: function(){
45352 if(!this.editorcore.activated){
45353 this.editor.onFirstFocus();
45357 var btns = this.tb.items.map,
45358 doc = this.editorcore.doc,
45359 frameId = this.editorcore.frameId;
45361 if(!this.disable.font && !Roo.isSafari){
45363 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45364 if(name != this.fontSelect.dom.value){
45365 this.fontSelect.dom.value = name;
45369 if(!this.disable.format){
45370 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45371 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45372 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45373 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45375 if(!this.disable.alignments){
45376 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45377 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45378 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45380 if(!Roo.isSafari && !this.disable.lists){
45381 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45382 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45385 var ans = this.editorcore.getAllAncestors();
45386 if (this.formatCombo) {
45389 var store = this.formatCombo.store;
45390 this.formatCombo.setValue("");
45391 for (var i =0; i < ans.length;i++) {
45392 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45394 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45402 // hides menus... - so this cant be on a menu...
45403 Roo.menu.MenuMgr.hideAll();
45405 //this.editorsyncValue();
45409 createFontOptions : function(){
45410 var buf = [], fs = this.fontFamilies, ff, lc;
45414 for(var i = 0, len = fs.length; i< len; i++){
45416 lc = ff.toLowerCase();
45418 '<option value="',lc,'" style="font-family:',ff,';"',
45419 (this.defaultFont == lc ? ' selected="true">' : '>'),
45424 return buf.join('');
45427 toggleSourceEdit : function(sourceEditMode){
45429 Roo.log("toolbar toogle");
45430 if(sourceEditMode === undefined){
45431 sourceEditMode = !this.sourceEditMode;
45433 this.sourceEditMode = sourceEditMode === true;
45434 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45435 // just toggle the button?
45436 if(btn.pressed !== this.sourceEditMode){
45437 btn.toggle(this.sourceEditMode);
45441 if(sourceEditMode){
45442 Roo.log("disabling buttons");
45443 this.tb.items.each(function(item){
45444 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45450 Roo.log("enabling buttons");
45451 if(this.editorcore.initialized){
45452 this.tb.items.each(function(item){
45458 Roo.log("calling toggole on editor");
45459 // tell the editor that it's been pressed..
45460 this.editor.toggleSourceEdit(sourceEditMode);
45464 * Object collection of toolbar tooltips for the buttons in the editor. The key
45465 * is the command id associated with that button and the value is a valid QuickTips object.
45470 title: 'Bold (Ctrl+B)',
45471 text: 'Make the selected text bold.',
45472 cls: 'x-html-editor-tip'
45475 title: 'Italic (Ctrl+I)',
45476 text: 'Make the selected text italic.',
45477 cls: 'x-html-editor-tip'
45485 title: 'Bold (Ctrl+B)',
45486 text: 'Make the selected text bold.',
45487 cls: 'x-html-editor-tip'
45490 title: 'Italic (Ctrl+I)',
45491 text: 'Make the selected text italic.',
45492 cls: 'x-html-editor-tip'
45495 title: 'Underline (Ctrl+U)',
45496 text: 'Underline the selected text.',
45497 cls: 'x-html-editor-tip'
45500 title: 'Strikethrough',
45501 text: 'Strikethrough the selected text.',
45502 cls: 'x-html-editor-tip'
45504 increasefontsize : {
45505 title: 'Grow Text',
45506 text: 'Increase the font size.',
45507 cls: 'x-html-editor-tip'
45509 decreasefontsize : {
45510 title: 'Shrink Text',
45511 text: 'Decrease the font size.',
45512 cls: 'x-html-editor-tip'
45515 title: 'Text Highlight Color',
45516 text: 'Change the background color of the selected text.',
45517 cls: 'x-html-editor-tip'
45520 title: 'Font Color',
45521 text: 'Change the color of the selected text.',
45522 cls: 'x-html-editor-tip'
45525 title: 'Align Text Left',
45526 text: 'Align text to the left.',
45527 cls: 'x-html-editor-tip'
45530 title: 'Center Text',
45531 text: 'Center text in the editor.',
45532 cls: 'x-html-editor-tip'
45535 title: 'Align Text Right',
45536 text: 'Align text to the right.',
45537 cls: 'x-html-editor-tip'
45539 insertunorderedlist : {
45540 title: 'Bullet List',
45541 text: 'Start a bulleted list.',
45542 cls: 'x-html-editor-tip'
45544 insertorderedlist : {
45545 title: 'Numbered List',
45546 text: 'Start a numbered list.',
45547 cls: 'x-html-editor-tip'
45550 title: 'Hyperlink',
45551 text: 'Make the selected text a hyperlink.',
45552 cls: 'x-html-editor-tip'
45555 title: 'Source Edit',
45556 text: 'Switch to source editing mode.',
45557 cls: 'x-html-editor-tip'
45561 onDestroy : function(){
45564 this.tb.items.each(function(item){
45566 item.menu.removeAll();
45568 item.menu.el.destroy();
45576 onFirstFocus: function() {
45577 this.tb.items.each(function(item){
45586 // <script type="text/javascript">
45589 * Ext JS Library 1.1.1
45590 * Copyright(c) 2006-2007, Ext JS, LLC.
45597 * @class Roo.form.HtmlEditor.ToolbarContext
45602 new Roo.form.HtmlEditor({
45605 { xtype: 'ToolbarStandard', styles : {} }
45606 { xtype: 'ToolbarContext', disable : {} }
45612 * @config : {Object} disable List of elements to disable.. (not done yet.)
45613 * @config : {Object} styles Map of styles available.
45617 Roo.form.HtmlEditor.ToolbarContext = function(config)
45620 Roo.apply(this, config);
45621 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45622 // dont call parent... till later.
45623 this.styles = this.styles || {};
45628 Roo.form.HtmlEditor.ToolbarContext.types = {
45640 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45706 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45711 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45721 style : 'fontFamily',
45722 displayField: 'display',
45723 optname : 'font-family',
45772 // should we really allow this??
45773 // should this just be
45784 style : 'fontFamily',
45785 displayField: 'display',
45786 optname : 'font-family',
45793 style : 'fontFamily',
45794 displayField: 'display',
45795 optname : 'font-family',
45802 style : 'fontFamily',
45803 displayField: 'display',
45804 optname : 'font-family',
45815 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45816 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45818 Roo.form.HtmlEditor.ToolbarContext.options = {
45820 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45821 [ 'Courier New', 'Courier New'],
45822 [ 'Tahoma', 'Tahoma'],
45823 [ 'Times New Roman,serif', 'Times'],
45824 [ 'Verdana','Verdana' ]
45828 // fixme - these need to be configurable..
45831 //Roo.form.HtmlEditor.ToolbarContext.types
45834 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45841 editorcore : false,
45843 * @cfg {Object} disable List of toolbar elements to disable
45848 * @cfg {Object} styles List of styles
45849 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
45851 * These must be defined in the page, so they get rendered correctly..
45862 init : function(editor)
45864 this.editor = editor;
45865 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45866 var editorcore = this.editorcore;
45868 var fid = editorcore.frameId;
45870 function btn(id, toggle, handler){
45871 var xid = fid + '-'+ id ;
45875 cls : 'x-btn-icon x-edit-'+id,
45876 enableToggle:toggle !== false,
45877 scope: editorcore, // was editor...
45878 handler:handler||editorcore.relayBtnCmd,
45879 clickEvent:'mousedown',
45880 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45884 // create a new element.
45885 var wdiv = editor.wrap.createChild({
45887 }, editor.wrap.dom.firstChild.nextSibling, true);
45889 // can we do this more than once??
45891 // stop form submits
45894 // disable everything...
45895 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
45896 this.toolbars = {};
45898 for (var i in ty) {
45900 this.toolbars[i] = this.buildToolbar(ty[i],i);
45902 this.tb = this.toolbars.BODY;
45904 this.buildFooter();
45905 this.footer.show();
45906 editor.on('hide', function( ) { this.footer.hide() }, this);
45907 editor.on('show', function( ) { this.footer.show() }, this);
45910 this.rendered = true;
45912 // the all the btns;
45913 editor.on('editorevent', this.updateToolbar, this);
45914 // other toolbars need to implement this..
45915 //editor.on('editmodechange', this.updateToolbar, this);
45921 * Protected method that will not generally be called directly. It triggers
45922 * a toolbar update by reading the markup state of the current selection in the editor.
45924 * Note you can force an update by calling on('editorevent', scope, false)
45926 updateToolbar: function(editor,ev,sel){
45929 // capture mouse up - this is handy for selecting images..
45930 // perhaps should go somewhere else...
45931 if(!this.editorcore.activated){
45932 this.editor.onFirstFocus();
45938 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
45939 // selectNode - might want to handle IE?
45941 (ev.type == 'mouseup' || ev.type == 'click' ) &&
45942 ev.target && ev.target.tagName == 'IMG') {
45943 // they have click on an image...
45944 // let's see if we can change the selection...
45947 var nodeRange = sel.ownerDocument.createRange();
45949 nodeRange.selectNode(sel);
45951 nodeRange.selectNodeContents(sel);
45953 //nodeRange.collapse(true);
45954 var s = this.editorcore.win.getSelection();
45955 s.removeAllRanges();
45956 s.addRange(nodeRange);
45960 var updateFooter = sel ? false : true;
45963 var ans = this.editorcore.getAllAncestors();
45966 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
45969 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
45970 sel = sel ? sel : this.editorcore.doc.body;
45971 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
45974 // pick a menu that exists..
45975 var tn = sel.tagName.toUpperCase();
45976 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
45978 tn = sel.tagName.toUpperCase();
45980 var lastSel = this.tb.selectedNode;
45982 this.tb.selectedNode = sel;
45984 // if current menu does not match..
45986 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
45989 ///console.log("show: " + tn);
45990 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
45993 this.tb.items.first().el.innerHTML = tn + ': ';
45996 // update attributes
45997 if (this.tb.fields) {
45998 this.tb.fields.each(function(e) {
46000 e.setValue(sel.style[e.stylename]);
46003 e.setValue(sel.getAttribute(e.attrname));
46007 var hasStyles = false;
46008 for(var i in this.styles) {
46015 var st = this.tb.fields.item(0);
46017 st.store.removeAll();
46020 var cn = sel.className.split(/\s+/);
46023 if (this.styles['*']) {
46025 Roo.each(this.styles['*'], function(v) {
46026 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46029 if (this.styles[tn]) {
46030 Roo.each(this.styles[tn], function(v) {
46031 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46035 st.store.loadData(avs);
46039 // flag our selected Node.
46040 this.tb.selectedNode = sel;
46043 Roo.menu.MenuMgr.hideAll();
46047 if (!updateFooter) {
46048 //this.footDisp.dom.innerHTML = '';
46051 // update the footer
46055 this.footerEls = ans.reverse();
46056 Roo.each(this.footerEls, function(a,i) {
46057 if (!a) { return; }
46058 html += html.length ? ' > ' : '';
46060 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46065 var sz = this.footDisp.up('td').getSize();
46066 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46067 this.footDisp.dom.style.marginLeft = '5px';
46069 this.footDisp.dom.style.overflow = 'hidden';
46071 this.footDisp.dom.innerHTML = html;
46073 //this.editorsyncValue();
46080 onDestroy : function(){
46083 this.tb.items.each(function(item){
46085 item.menu.removeAll();
46087 item.menu.el.destroy();
46095 onFirstFocus: function() {
46096 // need to do this for all the toolbars..
46097 this.tb.items.each(function(item){
46101 buildToolbar: function(tlist, nm)
46103 var editor = this.editor;
46104 var editorcore = this.editorcore;
46105 // create a new element.
46106 var wdiv = editor.wrap.createChild({
46108 }, editor.wrap.dom.firstChild.nextSibling, true);
46111 var tb = new Roo.Toolbar(wdiv);
46114 tb.add(nm+ ": ");
46117 for(var i in this.styles) {
46122 if (styles && styles.length) {
46124 // this needs a multi-select checkbox...
46125 tb.addField( new Roo.form.ComboBox({
46126 store: new Roo.data.SimpleStore({
46128 fields: ['val', 'selected'],
46131 name : '-roo-edit-className',
46132 attrname : 'className',
46133 displayField: 'val',
46137 triggerAction: 'all',
46138 emptyText:'Select Style',
46139 selectOnFocus:true,
46142 'select': function(c, r, i) {
46143 // initial support only for on class per el..
46144 tb.selectedNode.className = r ? r.get('val') : '';
46145 editorcore.syncValue();
46152 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46153 var tbops = tbc.options;
46155 for (var i in tlist) {
46157 var item = tlist[i];
46158 tb.add(item.title + ": ");
46161 //optname == used so you can configure the options available..
46162 var opts = item.opts ? item.opts : false;
46163 if (item.optname) {
46164 opts = tbops[item.optname];
46169 // opts == pulldown..
46170 tb.addField( new Roo.form.ComboBox({
46171 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46173 fields: ['val', 'display'],
46176 name : '-roo-edit-' + i,
46178 stylename : item.style ? item.style : false,
46179 displayField: item.displayField ? item.displayField : 'val',
46180 valueField : 'val',
46182 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46184 triggerAction: 'all',
46185 emptyText:'Select',
46186 selectOnFocus:true,
46187 width: item.width ? item.width : 130,
46189 'select': function(c, r, i) {
46191 tb.selectedNode.style[c.stylename] = r.get('val');
46194 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46203 tb.addField( new Roo.form.TextField({
46206 //allowBlank:false,
46211 tb.addField( new Roo.form.TextField({
46212 name: '-roo-edit-' + i,
46219 'change' : function(f, nv, ov) {
46220 tb.selectedNode.setAttribute(f.attrname, nv);
46221 editorcore.syncValue();
46234 text: 'Stylesheets',
46237 click : function ()
46239 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46247 text: 'Remove Tag',
46250 click : function ()
46253 // undo does not work.
46255 var sn = tb.selectedNode;
46257 var pn = sn.parentNode;
46259 var stn = sn.childNodes[0];
46260 var en = sn.childNodes[sn.childNodes.length - 1 ];
46261 while (sn.childNodes.length) {
46262 var node = sn.childNodes[0];
46263 sn.removeChild(node);
46265 pn.insertBefore(node, sn);
46268 pn.removeChild(sn);
46269 var range = editorcore.createRange();
46271 range.setStart(stn,0);
46272 range.setEnd(en,0); //????
46273 //range.selectNode(sel);
46276 var selection = editorcore.getSelection();
46277 selection.removeAllRanges();
46278 selection.addRange(range);
46282 //_this.updateToolbar(null, null, pn);
46283 _this.updateToolbar(null, null, null);
46284 _this.footDisp.dom.innerHTML = '';
46294 tb.el.on('click', function(e){
46295 e.preventDefault(); // what does this do?
46297 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46300 // dont need to disable them... as they will get hidden
46305 buildFooter : function()
46308 var fel = this.editor.wrap.createChild();
46309 this.footer = new Roo.Toolbar(fel);
46310 // toolbar has scrolly on left / right?
46311 var footDisp= new Roo.Toolbar.Fill();
46317 handler : function() {
46318 _t.footDisp.scrollTo('left',0,true)
46322 this.footer.add( footDisp );
46327 handler : function() {
46329 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46333 var fel = Roo.get(footDisp.el);
46334 fel.addClass('x-editor-context');
46335 this.footDispWrap = fel;
46336 this.footDispWrap.overflow = 'hidden';
46338 this.footDisp = fel.createChild();
46339 this.footDispWrap.on('click', this.onContextClick, this)
46343 onContextClick : function (ev,dom)
46345 ev.preventDefault();
46346 var cn = dom.className;
46348 if (!cn.match(/x-ed-loc-/)) {
46351 var n = cn.split('-').pop();
46352 var ans = this.footerEls;
46356 var range = this.editorcore.createRange();
46358 range.selectNodeContents(sel);
46359 //range.selectNode(sel);
46362 var selection = this.editorcore.getSelection();
46363 selection.removeAllRanges();
46364 selection.addRange(range);
46368 this.updateToolbar(null, null, sel);
46385 * Ext JS Library 1.1.1
46386 * Copyright(c) 2006-2007, Ext JS, LLC.
46388 * Originally Released Under LGPL - original licence link has changed is not relivant.
46391 * <script type="text/javascript">
46395 * @class Roo.form.BasicForm
46396 * @extends Roo.util.Observable
46397 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46399 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46400 * @param {Object} config Configuration options
46402 Roo.form.BasicForm = function(el, config){
46403 this.allItems = [];
46404 this.childForms = [];
46405 Roo.apply(this, config);
46407 * The Roo.form.Field items in this form.
46408 * @type MixedCollection
46412 this.items = new Roo.util.MixedCollection(false, function(o){
46413 return o.id || (o.id = Roo.id());
46417 * @event beforeaction
46418 * Fires before any action is performed. Return false to cancel the action.
46419 * @param {Form} this
46420 * @param {Action} action The action to be performed
46422 beforeaction: true,
46424 * @event actionfailed
46425 * Fires when an action fails.
46426 * @param {Form} this
46427 * @param {Action} action The action that failed
46429 actionfailed : true,
46431 * @event actioncomplete
46432 * Fires when an action is completed.
46433 * @param {Form} this
46434 * @param {Action} action The action that completed
46436 actioncomplete : true
46441 Roo.form.BasicForm.superclass.constructor.call(this);
46444 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46446 * @cfg {String} method
46447 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46450 * @cfg {DataReader} reader
46451 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46452 * This is optional as there is built-in support for processing JSON.
46455 * @cfg {DataReader} errorReader
46456 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46457 * This is completely optional as there is built-in support for processing JSON.
46460 * @cfg {String} url
46461 * The URL to use for form actions if one isn't supplied in the action options.
46464 * @cfg {Boolean} fileUpload
46465 * Set to true if this form is a file upload.
46469 * @cfg {Object} baseParams
46470 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46475 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46480 activeAction : null,
46483 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46484 * or setValues() data instead of when the form was first created.
46486 trackResetOnLoad : false,
46490 * childForms - used for multi-tab forms
46493 childForms : false,
46496 * allItems - full list of fields.
46502 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46503 * element by passing it or its id or mask the form itself by passing in true.
46506 waitMsgTarget : false,
46509 initEl : function(el){
46510 this.el = Roo.get(el);
46511 this.id = this.el.id || Roo.id();
46512 this.el.on('submit', this.onSubmit, this);
46513 this.el.addClass('x-form');
46517 onSubmit : function(e){
46522 * Returns true if client-side validation on the form is successful.
46525 isValid : function(){
46527 this.items.each(function(f){
46536 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46539 isDirty : function(){
46541 this.items.each(function(f){
46551 * Returns true if any fields in this form have changed since their original load. (New version)
46555 hasChanged : function()
46558 this.items.each(function(f){
46559 if(f.hasChanged()){
46568 * Resets all hasChanged to 'false' -
46569 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46570 * So hasChanged storage is only to be used for this purpose
46573 resetHasChanged : function()
46575 this.items.each(function(f){
46576 f.resetHasChanged();
46583 * Performs a predefined action (submit or load) or custom actions you define on this form.
46584 * @param {String} actionName The name of the action type
46585 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46586 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46587 * accept other config options):
46589 Property Type Description
46590 ---------------- --------------- ----------------------------------------------------------------------------------
46591 url String The url for the action (defaults to the form's url)
46592 method String The form method to use (defaults to the form's method, or POST if not defined)
46593 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46594 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46595 validate the form on the client (defaults to false)
46597 * @return {BasicForm} this
46599 doAction : function(action, options){
46600 if(typeof action == 'string'){
46601 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46603 if(this.fireEvent('beforeaction', this, action) !== false){
46604 this.beforeAction(action);
46605 action.run.defer(100, action);
46611 * Shortcut to do a submit action.
46612 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46613 * @return {BasicForm} this
46615 submit : function(options){
46616 this.doAction('submit', options);
46621 * Shortcut to do a load action.
46622 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46623 * @return {BasicForm} this
46625 load : function(options){
46626 this.doAction('load', options);
46631 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46632 * @param {Record} record The record to edit
46633 * @return {BasicForm} this
46635 updateRecord : function(record){
46636 record.beginEdit();
46637 var fs = record.fields;
46638 fs.each(function(f){
46639 var field = this.findField(f.name);
46641 record.set(f.name, field.getValue());
46649 * Loads an Roo.data.Record into this form.
46650 * @param {Record} record The record to load
46651 * @return {BasicForm} this
46653 loadRecord : function(record){
46654 this.setValues(record.data);
46659 beforeAction : function(action){
46660 var o = action.options;
46663 if(this.waitMsgTarget === true){
46664 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46665 }else if(this.waitMsgTarget){
46666 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46667 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46669 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46675 afterAction : function(action, success){
46676 this.activeAction = null;
46677 var o = action.options;
46679 if(this.waitMsgTarget === true){
46681 }else if(this.waitMsgTarget){
46682 this.waitMsgTarget.unmask();
46684 Roo.MessageBox.updateProgress(1);
46685 Roo.MessageBox.hide();
46692 Roo.callback(o.success, o.scope, [this, action]);
46693 this.fireEvent('actioncomplete', this, action);
46697 // failure condition..
46698 // we have a scenario where updates need confirming.
46699 // eg. if a locking scenario exists..
46700 // we look for { errors : { needs_confirm : true }} in the response.
46702 (typeof(action.result) != 'undefined') &&
46703 (typeof(action.result.errors) != 'undefined') &&
46704 (typeof(action.result.errors.needs_confirm) != 'undefined')
46707 Roo.MessageBox.confirm(
46708 "Change requires confirmation",
46709 action.result.errorMsg,
46714 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46724 Roo.callback(o.failure, o.scope, [this, action]);
46725 // show an error message if no failed handler is set..
46726 if (!this.hasListener('actionfailed')) {
46727 Roo.MessageBox.alert("Error",
46728 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46729 action.result.errorMsg :
46730 "Saving Failed, please check your entries or try again"
46734 this.fireEvent('actionfailed', this, action);
46740 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46741 * @param {String} id The value to search for
46744 findField : function(id){
46745 var field = this.items.get(id);
46747 this.items.each(function(f){
46748 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46754 return field || null;
46758 * Add a secondary form to this one,
46759 * Used to provide tabbed forms. One form is primary, with hidden values
46760 * which mirror the elements from the other forms.
46762 * @param {Roo.form.Form} form to add.
46765 addForm : function(form)
46768 if (this.childForms.indexOf(form) > -1) {
46772 this.childForms.push(form);
46774 Roo.each(form.allItems, function (fe) {
46776 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46777 if (this.findField(n)) { // already added..
46780 var add = new Roo.form.Hidden({
46783 add.render(this.el);
46790 * Mark fields in this form invalid in bulk.
46791 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46792 * @return {BasicForm} this
46794 markInvalid : function(errors){
46795 if(errors instanceof Array){
46796 for(var i = 0, len = errors.length; i < len; i++){
46797 var fieldError = errors[i];
46798 var f = this.findField(fieldError.id);
46800 f.markInvalid(fieldError.msg);
46806 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46807 field.markInvalid(errors[id]);
46811 Roo.each(this.childForms || [], function (f) {
46812 f.markInvalid(errors);
46819 * Set values for fields in this form in bulk.
46820 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46821 * @return {BasicForm} this
46823 setValues : function(values){
46824 if(values instanceof Array){ // array of objects
46825 for(var i = 0, len = values.length; i < len; i++){
46827 var f = this.findField(v.id);
46829 f.setValue(v.value);
46830 if(this.trackResetOnLoad){
46831 f.originalValue = f.getValue();
46835 }else{ // object hash
46838 if(typeof values[id] != 'function' && (field = this.findField(id))){
46840 if (field.setFromData &&
46841 field.valueField &&
46842 field.displayField &&
46843 // combos' with local stores can
46844 // be queried via setValue()
46845 // to set their value..
46846 (field.store && !field.store.isLocal)
46850 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
46851 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
46852 field.setFromData(sd);
46855 field.setValue(values[id]);
46859 if(this.trackResetOnLoad){
46860 field.originalValue = field.getValue();
46865 this.resetHasChanged();
46868 Roo.each(this.childForms || [], function (f) {
46869 f.setValues(values);
46870 f.resetHasChanged();
46877 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
46878 * they are returned as an array.
46879 * @param {Boolean} asString
46882 getValues : function(asString){
46883 if (this.childForms) {
46884 // copy values from the child forms
46885 Roo.each(this.childForms, function (f) {
46886 this.setValues(f.getValues());
46892 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
46893 if(asString === true){
46896 return Roo.urlDecode(fs);
46900 * Returns the fields in this form as an object with key/value pairs.
46901 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
46904 getFieldValues : function(with_hidden)
46906 if (this.childForms) {
46907 // copy values from the child forms
46908 // should this call getFieldValues - probably not as we do not currently copy
46909 // hidden fields when we generate..
46910 Roo.each(this.childForms, function (f) {
46911 this.setValues(f.getValues());
46916 this.items.each(function(f){
46917 if (!f.getName()) {
46920 var v = f.getValue();
46921 if (f.inputType =='radio') {
46922 if (typeof(ret[f.getName()]) == 'undefined') {
46923 ret[f.getName()] = ''; // empty..
46926 if (!f.el.dom.checked) {
46930 v = f.el.dom.value;
46934 // not sure if this supported any more..
46935 if ((typeof(v) == 'object') && f.getRawValue) {
46936 v = f.getRawValue() ; // dates..
46938 // combo boxes where name != hiddenName...
46939 if (f.name != f.getName()) {
46940 ret[f.name] = f.getRawValue();
46942 ret[f.getName()] = v;
46949 * Clears all invalid messages in this form.
46950 * @return {BasicForm} this
46952 clearInvalid : function(){
46953 this.items.each(function(f){
46957 Roo.each(this.childForms || [], function (f) {
46966 * Resets this form.
46967 * @return {BasicForm} this
46969 reset : function(){
46970 this.items.each(function(f){
46974 Roo.each(this.childForms || [], function (f) {
46977 this.resetHasChanged();
46983 * Add Roo.form components to this form.
46984 * @param {Field} field1
46985 * @param {Field} field2 (optional)
46986 * @param {Field} etc (optional)
46987 * @return {BasicForm} this
46990 this.items.addAll(Array.prototype.slice.call(arguments, 0));
46996 * Removes a field from the items collection (does NOT remove its markup).
46997 * @param {Field} field
46998 * @return {BasicForm} this
47000 remove : function(field){
47001 this.items.remove(field);
47006 * Looks at the fields in this form, checks them for an id attribute,
47007 * and calls applyTo on the existing dom element with that id.
47008 * @return {BasicForm} this
47010 render : function(){
47011 this.items.each(function(f){
47012 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47020 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47021 * @param {Object} values
47022 * @return {BasicForm} this
47024 applyToFields : function(o){
47025 this.items.each(function(f){
47032 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47033 * @param {Object} values
47034 * @return {BasicForm} this
47036 applyIfToFields : function(o){
47037 this.items.each(function(f){
47045 Roo.BasicForm = Roo.form.BasicForm;/*
47047 * Ext JS Library 1.1.1
47048 * Copyright(c) 2006-2007, Ext JS, LLC.
47050 * Originally Released Under LGPL - original licence link has changed is not relivant.
47053 * <script type="text/javascript">
47057 * @class Roo.form.Form
47058 * @extends Roo.form.BasicForm
47059 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47061 * @param {Object} config Configuration options
47063 Roo.form.Form = function(config){
47065 if (config.items) {
47066 xitems = config.items;
47067 delete config.items;
47071 Roo.form.Form.superclass.constructor.call(this, null, config);
47072 this.url = this.url || this.action;
47074 this.root = new Roo.form.Layout(Roo.applyIf({
47078 this.active = this.root;
47080 * Array of all the buttons that have been added to this form via {@link addButton}
47084 this.allItems = [];
47087 * @event clientvalidation
47088 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47089 * @param {Form} this
47090 * @param {Boolean} valid true if the form has passed client-side validation
47092 clientvalidation: true,
47095 * Fires when the form is rendered
47096 * @param {Roo.form.Form} form
47101 if (this.progressUrl) {
47102 // push a hidden field onto the list of fields..
47106 name : 'UPLOAD_IDENTIFIER'
47111 Roo.each(xitems, this.addxtype, this);
47117 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47119 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47122 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47125 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47127 buttonAlign:'center',
47130 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47135 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47136 * This property cascades to child containers if not set.
47141 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47142 * fires a looping event with that state. This is required to bind buttons to the valid
47143 * state using the config value formBind:true on the button.
47145 monitorValid : false,
47148 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47153 * @cfg {String} progressUrl - Url to return progress data
47156 progressUrl : false,
47159 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47160 * fields are added and the column is closed. If no fields are passed the column remains open
47161 * until end() is called.
47162 * @param {Object} config The config to pass to the column
47163 * @param {Field} field1 (optional)
47164 * @param {Field} field2 (optional)
47165 * @param {Field} etc (optional)
47166 * @return Column The column container object
47168 column : function(c){
47169 var col = new Roo.form.Column(c);
47171 if(arguments.length > 1){ // duplicate code required because of Opera
47172 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47179 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47180 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47181 * until end() is called.
47182 * @param {Object} config The config to pass to the fieldset
47183 * @param {Field} field1 (optional)
47184 * @param {Field} field2 (optional)
47185 * @param {Field} etc (optional)
47186 * @return FieldSet The fieldset container object
47188 fieldset : function(c){
47189 var fs = new Roo.form.FieldSet(c);
47191 if(arguments.length > 1){ // duplicate code required because of Opera
47192 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47199 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47200 * fields are added and the container is closed. If no fields are passed the container remains open
47201 * until end() is called.
47202 * @param {Object} config The config to pass to the Layout
47203 * @param {Field} field1 (optional)
47204 * @param {Field} field2 (optional)
47205 * @param {Field} etc (optional)
47206 * @return Layout The container object
47208 container : function(c){
47209 var l = new Roo.form.Layout(c);
47211 if(arguments.length > 1){ // duplicate code required because of Opera
47212 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47219 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47220 * @param {Object} container A Roo.form.Layout or subclass of Layout
47221 * @return {Form} this
47223 start : function(c){
47224 // cascade label info
47225 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47226 this.active.stack.push(c);
47227 c.ownerCt = this.active;
47233 * Closes the current open container
47234 * @return {Form} this
47237 if(this.active == this.root){
47240 this.active = this.active.ownerCt;
47245 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47246 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47247 * as the label of the field.
47248 * @param {Field} field1
47249 * @param {Field} field2 (optional)
47250 * @param {Field} etc. (optional)
47251 * @return {Form} this
47254 this.active.stack.push.apply(this.active.stack, arguments);
47255 this.allItems.push.apply(this.allItems,arguments);
47257 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47258 if(a[i].isFormField){
47263 Roo.form.Form.superclass.add.apply(this, r);
47273 * Find any element that has been added to a form, using it's ID or name
47274 * This can include framesets, columns etc. along with regular fields..
47275 * @param {String} id - id or name to find.
47277 * @return {Element} e - or false if nothing found.
47279 findbyId : function(id)
47285 Roo.each(this.allItems, function(f){
47286 if (f.id == id || f.name == id ){
47297 * Render this form into the passed container. This should only be called once!
47298 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47299 * @return {Form} this
47301 render : function(ct)
47307 var o = this.autoCreate || {
47309 method : this.method || 'POST',
47310 id : this.id || Roo.id()
47312 this.initEl(ct.createChild(o));
47314 this.root.render(this.el);
47318 this.items.each(function(f){
47319 f.render('x-form-el-'+f.id);
47322 if(this.buttons.length > 0){
47323 // tables are required to maintain order and for correct IE layout
47324 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47325 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47326 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47328 var tr = tb.getElementsByTagName('tr')[0];
47329 for(var i = 0, len = this.buttons.length; i < len; i++) {
47330 var b = this.buttons[i];
47331 var td = document.createElement('td');
47332 td.className = 'x-form-btn-td';
47333 b.render(tr.appendChild(td));
47336 if(this.monitorValid){ // initialize after render
47337 this.startMonitoring();
47339 this.fireEvent('rendered', this);
47344 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47345 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47346 * object or a valid Roo.DomHelper element config
47347 * @param {Function} handler The function called when the button is clicked
47348 * @param {Object} scope (optional) The scope of the handler function
47349 * @return {Roo.Button}
47351 addButton : function(config, handler, scope){
47355 minWidth: this.minButtonWidth,
47358 if(typeof config == "string"){
47361 Roo.apply(bc, config);
47363 var btn = new Roo.Button(null, bc);
47364 this.buttons.push(btn);
47369 * Adds a series of form elements (using the xtype property as the factory method.
47370 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47371 * @param {Object} config
47374 addxtype : function()
47376 var ar = Array.prototype.slice.call(arguments, 0);
47378 for(var i = 0; i < ar.length; i++) {
47380 continue; // skip -- if this happends something invalid got sent, we
47381 // should ignore it, as basically that interface element will not show up
47382 // and that should be pretty obvious!!
47385 if (Roo.form[ar[i].xtype]) {
47387 var fe = Roo.factory(ar[i], Roo.form);
47393 fe.store.form = this;
47398 this.allItems.push(fe);
47399 if (fe.items && fe.addxtype) {
47400 fe.addxtype.apply(fe, fe.items);
47410 // console.log('adding ' + ar[i].xtype);
47412 if (ar[i].xtype == 'Button') {
47413 //console.log('adding button');
47414 //console.log(ar[i]);
47415 this.addButton(ar[i]);
47416 this.allItems.push(fe);
47420 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47421 alert('end is not supported on xtype any more, use items');
47423 // //console.log('adding end');
47431 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47432 * option "monitorValid"
47434 startMonitoring : function(){
47437 Roo.TaskMgr.start({
47438 run : this.bindHandler,
47439 interval : this.monitorPoll || 200,
47446 * Stops monitoring of the valid state of this form
47448 stopMonitoring : function(){
47449 this.bound = false;
47453 bindHandler : function(){
47455 return false; // stops binding
47458 this.items.each(function(f){
47459 if(!f.isValid(true)){
47464 for(var i = 0, len = this.buttons.length; i < len; i++){
47465 var btn = this.buttons[i];
47466 if(btn.formBind === true && btn.disabled === valid){
47467 btn.setDisabled(!valid);
47470 this.fireEvent('clientvalidation', this, valid);
47484 Roo.Form = Roo.form.Form;
47487 * Ext JS Library 1.1.1
47488 * Copyright(c) 2006-2007, Ext JS, LLC.
47490 * Originally Released Under LGPL - original licence link has changed is not relivant.
47493 * <script type="text/javascript">
47496 // as we use this in bootstrap.
47497 Roo.namespace('Roo.form');
47499 * @class Roo.form.Action
47500 * Internal Class used to handle form actions
47502 * @param {Roo.form.BasicForm} el The form element or its id
47503 * @param {Object} config Configuration options
47508 // define the action interface
47509 Roo.form.Action = function(form, options){
47511 this.options = options || {};
47514 * Client Validation Failed
47517 Roo.form.Action.CLIENT_INVALID = 'client';
47519 * Server Validation Failed
47522 Roo.form.Action.SERVER_INVALID = 'server';
47524 * Connect to Server Failed
47527 Roo.form.Action.CONNECT_FAILURE = 'connect';
47529 * Reading Data from Server Failed
47532 Roo.form.Action.LOAD_FAILURE = 'load';
47534 Roo.form.Action.prototype = {
47536 failureType : undefined,
47537 response : undefined,
47538 result : undefined,
47540 // interface method
47541 run : function(options){
47545 // interface method
47546 success : function(response){
47550 // interface method
47551 handleResponse : function(response){
47555 // default connection failure
47556 failure : function(response){
47558 this.response = response;
47559 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47560 this.form.afterAction(this, false);
47563 processResponse : function(response){
47564 this.response = response;
47565 if(!response.responseText){
47568 this.result = this.handleResponse(response);
47569 return this.result;
47572 // utility functions used internally
47573 getUrl : function(appendParams){
47574 var url = this.options.url || this.form.url || this.form.el.dom.action;
47576 var p = this.getParams();
47578 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47584 getMethod : function(){
47585 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47588 getParams : function(){
47589 var bp = this.form.baseParams;
47590 var p = this.options.params;
47592 if(typeof p == "object"){
47593 p = Roo.urlEncode(Roo.applyIf(p, bp));
47594 }else if(typeof p == 'string' && bp){
47595 p += '&' + Roo.urlEncode(bp);
47598 p = Roo.urlEncode(bp);
47603 createCallback : function(){
47605 success: this.success,
47606 failure: this.failure,
47608 timeout: (this.form.timeout*1000),
47609 upload: this.form.fileUpload ? this.success : undefined
47614 Roo.form.Action.Submit = function(form, options){
47615 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47618 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47621 haveProgress : false,
47622 uploadComplete : false,
47624 // uploadProgress indicator.
47625 uploadProgress : function()
47627 if (!this.form.progressUrl) {
47631 if (!this.haveProgress) {
47632 Roo.MessageBox.progress("Uploading", "Uploading");
47634 if (this.uploadComplete) {
47635 Roo.MessageBox.hide();
47639 this.haveProgress = true;
47641 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47643 var c = new Roo.data.Connection();
47645 url : this.form.progressUrl,
47650 success : function(req){
47651 //console.log(data);
47655 rdata = Roo.decode(req.responseText)
47657 Roo.log("Invalid data from server..");
47661 if (!rdata || !rdata.success) {
47663 Roo.MessageBox.alert(Roo.encode(rdata));
47666 var data = rdata.data;
47668 if (this.uploadComplete) {
47669 Roo.MessageBox.hide();
47674 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47675 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47678 this.uploadProgress.defer(2000,this);
47681 failure: function(data) {
47682 Roo.log('progress url failed ');
47693 // run get Values on the form, so it syncs any secondary forms.
47694 this.form.getValues();
47696 var o = this.options;
47697 var method = this.getMethod();
47698 var isPost = method == 'POST';
47699 if(o.clientValidation === false || this.form.isValid()){
47701 if (this.form.progressUrl) {
47702 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47703 (new Date() * 1) + '' + Math.random());
47708 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47709 form:this.form.el.dom,
47710 url:this.getUrl(!isPost),
47712 params:isPost ? this.getParams() : null,
47713 isUpload: this.form.fileUpload
47716 this.uploadProgress();
47718 }else if (o.clientValidation !== false){ // client validation failed
47719 this.failureType = Roo.form.Action.CLIENT_INVALID;
47720 this.form.afterAction(this, false);
47724 success : function(response)
47726 this.uploadComplete= true;
47727 if (this.haveProgress) {
47728 Roo.MessageBox.hide();
47732 var result = this.processResponse(response);
47733 if(result === true || result.success){
47734 this.form.afterAction(this, true);
47738 this.form.markInvalid(result.errors);
47739 this.failureType = Roo.form.Action.SERVER_INVALID;
47741 this.form.afterAction(this, false);
47743 failure : function(response)
47745 this.uploadComplete= true;
47746 if (this.haveProgress) {
47747 Roo.MessageBox.hide();
47750 this.response = response;
47751 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47752 this.form.afterAction(this, false);
47755 handleResponse : function(response){
47756 if(this.form.errorReader){
47757 var rs = this.form.errorReader.read(response);
47760 for(var i = 0, len = rs.records.length; i < len; i++) {
47761 var r = rs.records[i];
47762 errors[i] = r.data;
47765 if(errors.length < 1){
47769 success : rs.success,
47775 ret = Roo.decode(response.responseText);
47779 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47789 Roo.form.Action.Load = function(form, options){
47790 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47791 this.reader = this.form.reader;
47794 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47799 Roo.Ajax.request(Roo.apply(
47800 this.createCallback(), {
47801 method:this.getMethod(),
47802 url:this.getUrl(false),
47803 params:this.getParams()
47807 success : function(response){
47809 var result = this.processResponse(response);
47810 if(result === true || !result.success || !result.data){
47811 this.failureType = Roo.form.Action.LOAD_FAILURE;
47812 this.form.afterAction(this, false);
47815 this.form.clearInvalid();
47816 this.form.setValues(result.data);
47817 this.form.afterAction(this, true);
47820 handleResponse : function(response){
47821 if(this.form.reader){
47822 var rs = this.form.reader.read(response);
47823 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47825 success : rs.success,
47829 return Roo.decode(response.responseText);
47833 Roo.form.Action.ACTION_TYPES = {
47834 'load' : Roo.form.Action.Load,
47835 'submit' : Roo.form.Action.Submit
47838 * Ext JS Library 1.1.1
47839 * Copyright(c) 2006-2007, Ext JS, LLC.
47841 * Originally Released Under LGPL - original licence link has changed is not relivant.
47844 * <script type="text/javascript">
47848 * @class Roo.form.Layout
47849 * @extends Roo.Component
47850 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
47852 * @param {Object} config Configuration options
47854 Roo.form.Layout = function(config){
47856 if (config.items) {
47857 xitems = config.items;
47858 delete config.items;
47860 Roo.form.Layout.superclass.constructor.call(this, config);
47862 Roo.each(xitems, this.addxtype, this);
47866 Roo.extend(Roo.form.Layout, Roo.Component, {
47868 * @cfg {String/Object} autoCreate
47869 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
47872 * @cfg {String/Object/Function} style
47873 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
47874 * a function which returns such a specification.
47877 * @cfg {String} labelAlign
47878 * Valid values are "left," "top" and "right" (defaults to "left")
47881 * @cfg {Number} labelWidth
47882 * Fixed width in pixels of all field labels (defaults to undefined)
47885 * @cfg {Boolean} clear
47886 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
47890 * @cfg {String} labelSeparator
47891 * The separator to use after field labels (defaults to ':')
47893 labelSeparator : ':',
47895 * @cfg {Boolean} hideLabels
47896 * True to suppress the display of field labels in this layout (defaults to false)
47898 hideLabels : false,
47901 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
47906 onRender : function(ct, position){
47907 if(this.el){ // from markup
47908 this.el = Roo.get(this.el);
47909 }else { // generate
47910 var cfg = this.getAutoCreate();
47911 this.el = ct.createChild(cfg, position);
47914 this.el.applyStyles(this.style);
47916 if(this.labelAlign){
47917 this.el.addClass('x-form-label-'+this.labelAlign);
47919 if(this.hideLabels){
47920 this.labelStyle = "display:none";
47921 this.elementStyle = "padding-left:0;";
47923 if(typeof this.labelWidth == 'number'){
47924 this.labelStyle = "width:"+this.labelWidth+"px;";
47925 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
47927 if(this.labelAlign == 'top'){
47928 this.labelStyle = "width:auto;";
47929 this.elementStyle = "padding-left:0;";
47932 var stack = this.stack;
47933 var slen = stack.length;
47935 if(!this.fieldTpl){
47936 var t = new Roo.Template(
47937 '<div class="x-form-item {5}">',
47938 '<label for="{0}" style="{2}">{1}{4}</label>',
47939 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
47941 '</div><div class="x-form-clear-left"></div>'
47943 t.disableFormats = true;
47945 Roo.form.Layout.prototype.fieldTpl = t;
47947 for(var i = 0; i < slen; i++) {
47948 if(stack[i].isFormField){
47949 this.renderField(stack[i]);
47951 this.renderComponent(stack[i]);
47956 this.el.createChild({cls:'x-form-clear'});
47961 renderField : function(f){
47962 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
47965 f.labelStyle||this.labelStyle||'', //2
47966 this.elementStyle||'', //3
47967 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
47968 f.itemCls||this.itemCls||'' //5
47969 ], true).getPrevSibling());
47973 renderComponent : function(c){
47974 c.render(c.isLayout ? this.el : this.el.createChild());
47977 * Adds a object form elements (using the xtype property as the factory method.)
47978 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
47979 * @param {Object} config
47981 addxtype : function(o)
47983 // create the lement.
47984 o.form = this.form;
47985 var fe = Roo.factory(o, Roo.form);
47986 this.form.allItems.push(fe);
47987 this.stack.push(fe);
47989 if (fe.isFormField) {
47990 this.form.items.add(fe);
47998 * @class Roo.form.Column
47999 * @extends Roo.form.Layout
48000 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48002 * @param {Object} config Configuration options
48004 Roo.form.Column = function(config){
48005 Roo.form.Column.superclass.constructor.call(this, config);
48008 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48010 * @cfg {Number/String} width
48011 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48014 * @cfg {String/Object} autoCreate
48015 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48019 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48022 onRender : function(ct, position){
48023 Roo.form.Column.superclass.onRender.call(this, ct, position);
48025 this.el.setWidth(this.width);
48032 * @class Roo.form.Row
48033 * @extends Roo.form.Layout
48034 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48036 * @param {Object} config Configuration options
48040 Roo.form.Row = function(config){
48041 Roo.form.Row.superclass.constructor.call(this, config);
48044 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48046 * @cfg {Number/String} width
48047 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48050 * @cfg {Number/String} height
48051 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48053 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48057 onRender : function(ct, position){
48058 //console.log('row render');
48060 var t = new Roo.Template(
48061 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48062 '<label for="{0}" style="{2}">{1}{4}</label>',
48063 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48067 t.disableFormats = true;
48069 Roo.form.Layout.prototype.rowTpl = t;
48071 this.fieldTpl = this.rowTpl;
48073 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48074 var labelWidth = 100;
48076 if ((this.labelAlign != 'top')) {
48077 if (typeof this.labelWidth == 'number') {
48078 labelWidth = this.labelWidth
48080 this.padWidth = 20 + labelWidth;
48084 Roo.form.Column.superclass.onRender.call(this, ct, position);
48086 this.el.setWidth(this.width);
48089 this.el.setHeight(this.height);
48094 renderField : function(f){
48095 f.fieldEl = this.fieldTpl.append(this.el, [
48096 f.id, f.fieldLabel,
48097 f.labelStyle||this.labelStyle||'',
48098 this.elementStyle||'',
48099 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48100 f.itemCls||this.itemCls||'',
48101 f.width ? f.width + this.padWidth : 160 + this.padWidth
48108 * @class Roo.form.FieldSet
48109 * @extends Roo.form.Layout
48110 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48112 * @param {Object} config Configuration options
48114 Roo.form.FieldSet = function(config){
48115 Roo.form.FieldSet.superclass.constructor.call(this, config);
48118 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48120 * @cfg {String} legend
48121 * The text to display as the legend for the FieldSet (defaults to '')
48124 * @cfg {String/Object} autoCreate
48125 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48129 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48132 onRender : function(ct, position){
48133 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48135 this.setLegend(this.legend);
48140 setLegend : function(text){
48142 this.el.child('legend').update(text);
48147 * Ext JS Library 1.1.1
48148 * Copyright(c) 2006-2007, Ext JS, LLC.
48150 * Originally Released Under LGPL - original licence link has changed is not relivant.
48153 * <script type="text/javascript">
48156 * @class Roo.form.VTypes
48157 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48160 Roo.form.VTypes = function(){
48161 // closure these in so they are only created once.
48162 var alpha = /^[a-zA-Z_]+$/;
48163 var alphanum = /^[a-zA-Z0-9_]+$/;
48164 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48165 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48167 // All these messages and functions are configurable
48170 * The function used to validate email addresses
48171 * @param {String} value The email address
48173 'email' : function(v){
48174 return email.test(v);
48177 * The error text to display when the email validation function returns false
48180 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48182 * The keystroke filter mask to be applied on email input
48185 'emailMask' : /[a-z0-9_\.\-@]/i,
48188 * The function used to validate URLs
48189 * @param {String} value The URL
48191 'url' : function(v){
48192 return url.test(v);
48195 * The error text to display when the url validation function returns false
48198 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48201 * The function used to validate alpha values
48202 * @param {String} value The value
48204 'alpha' : function(v){
48205 return alpha.test(v);
48208 * The error text to display when the alpha validation function returns false
48211 'alphaText' : 'This field should only contain letters and _',
48213 * The keystroke filter mask to be applied on alpha input
48216 'alphaMask' : /[a-z_]/i,
48219 * The function used to validate alphanumeric values
48220 * @param {String} value The value
48222 'alphanum' : function(v){
48223 return alphanum.test(v);
48226 * The error text to display when the alphanumeric validation function returns false
48229 'alphanumText' : 'This field should only contain letters, numbers and _',
48231 * The keystroke filter mask to be applied on alphanumeric input
48234 'alphanumMask' : /[a-z0-9_]/i
48236 }();//<script type="text/javascript">
48239 * @class Roo.form.FCKeditor
48240 * @extends Roo.form.TextArea
48241 * Wrapper around the FCKEditor http://www.fckeditor.net
48243 * Creates a new FCKeditor
48244 * @param {Object} config Configuration options
48246 Roo.form.FCKeditor = function(config){
48247 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48250 * @event editorinit
48251 * Fired when the editor is initialized - you can add extra handlers here..
48252 * @param {FCKeditor} this
48253 * @param {Object} the FCK object.
48260 Roo.form.FCKeditor.editors = { };
48261 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48263 //defaultAutoCreate : {
48264 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48268 * @cfg {Object} fck options - see fck manual for details.
48273 * @cfg {Object} fck toolbar set (Basic or Default)
48275 toolbarSet : 'Basic',
48277 * @cfg {Object} fck BasePath
48279 basePath : '/fckeditor/',
48287 onRender : function(ct, position)
48290 this.defaultAutoCreate = {
48292 style:"width:300px;height:60px;",
48293 autocomplete: "new-password"
48296 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48299 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48300 if(this.preventScrollbars){
48301 this.el.setStyle("overflow", "hidden");
48303 this.el.setHeight(this.growMin);
48306 //console.log('onrender' + this.getId() );
48307 Roo.form.FCKeditor.editors[this.getId()] = this;
48310 this.replaceTextarea() ;
48314 getEditor : function() {
48315 return this.fckEditor;
48318 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48319 * @param {Mixed} value The value to set
48323 setValue : function(value)
48325 //console.log('setValue: ' + value);
48327 if(typeof(value) == 'undefined') { // not sure why this is happending...
48330 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48332 //if(!this.el || !this.getEditor()) {
48333 // this.value = value;
48334 //this.setValue.defer(100,this,[value]);
48338 if(!this.getEditor()) {
48342 this.getEditor().SetData(value);
48349 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48350 * @return {Mixed} value The field value
48352 getValue : function()
48355 if (this.frame && this.frame.dom.style.display == 'none') {
48356 return Roo.form.FCKeditor.superclass.getValue.call(this);
48359 if(!this.el || !this.getEditor()) {
48361 // this.getValue.defer(100,this);
48366 var value=this.getEditor().GetData();
48367 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48368 return Roo.form.FCKeditor.superclass.getValue.call(this);
48374 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48375 * @return {Mixed} value The field value
48377 getRawValue : function()
48379 if (this.frame && this.frame.dom.style.display == 'none') {
48380 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48383 if(!this.el || !this.getEditor()) {
48384 //this.getRawValue.defer(100,this);
48391 var value=this.getEditor().GetData();
48392 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48393 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48397 setSize : function(w,h) {
48401 //if (this.frame && this.frame.dom.style.display == 'none') {
48402 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48405 //if(!this.el || !this.getEditor()) {
48406 // this.setSize.defer(100,this, [w,h]);
48412 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48414 this.frame.dom.setAttribute('width', w);
48415 this.frame.dom.setAttribute('height', h);
48416 this.frame.setSize(w,h);
48420 toggleSourceEdit : function(value) {
48424 this.el.dom.style.display = value ? '' : 'none';
48425 this.frame.dom.style.display = value ? 'none' : '';
48430 focus: function(tag)
48432 if (this.frame.dom.style.display == 'none') {
48433 return Roo.form.FCKeditor.superclass.focus.call(this);
48435 if(!this.el || !this.getEditor()) {
48436 this.focus.defer(100,this, [tag]);
48443 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48444 this.getEditor().Focus();
48446 if (!this.getEditor().Selection.GetSelection()) {
48447 this.focus.defer(100,this, [tag]);
48452 var r = this.getEditor().EditorDocument.createRange();
48453 r.setStart(tgs[0],0);
48454 r.setEnd(tgs[0],0);
48455 this.getEditor().Selection.GetSelection().removeAllRanges();
48456 this.getEditor().Selection.GetSelection().addRange(r);
48457 this.getEditor().Focus();
48464 replaceTextarea : function()
48466 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48469 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48471 // We must check the elements firstly using the Id and then the name.
48472 var oTextarea = document.getElementById( this.getId() );
48474 var colElementsByName = document.getElementsByName( this.getId() ) ;
48476 oTextarea.style.display = 'none' ;
48478 if ( oTextarea.tabIndex ) {
48479 this.TabIndex = oTextarea.tabIndex ;
48482 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48483 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48484 this.frame = Roo.get(this.getId() + '___Frame')
48487 _getConfigHtml : function()
48491 for ( var o in this.fckconfig ) {
48492 sConfig += sConfig.length > 0 ? '&' : '';
48493 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48496 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48500 _getIFrameHtml : function()
48502 var sFile = 'fckeditor.html' ;
48503 /* no idea what this is about..
48506 if ( (/fcksource=true/i).test( window.top.location.search ) )
48507 sFile = 'fckeditor.original.html' ;
48512 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48513 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48516 var html = '<iframe id="' + this.getId() +
48517 '___Frame" src="' + sLink +
48518 '" width="' + this.width +
48519 '" height="' + this.height + '"' +
48520 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48521 ' frameborder="0" scrolling="no"></iframe>' ;
48526 _insertHtmlBefore : function( html, element )
48528 if ( element.insertAdjacentHTML ) {
48530 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48532 var oRange = document.createRange() ;
48533 oRange.setStartBefore( element ) ;
48534 var oFragment = oRange.createContextualFragment( html );
48535 element.parentNode.insertBefore( oFragment, element ) ;
48548 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48550 function FCKeditor_OnComplete(editorInstance){
48551 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48552 f.fckEditor = editorInstance;
48553 //console.log("loaded");
48554 f.fireEvent('editorinit', f, editorInstance);
48574 //<script type="text/javascript">
48576 * @class Roo.form.GridField
48577 * @extends Roo.form.Field
48578 * Embed a grid (or editable grid into a form)
48581 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48583 * xgrid.store = Roo.data.Store
48584 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48585 * xgrid.store.reader = Roo.data.JsonReader
48589 * Creates a new GridField
48590 * @param {Object} config Configuration options
48592 Roo.form.GridField = function(config){
48593 Roo.form.GridField.superclass.constructor.call(this, config);
48597 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48599 * @cfg {Number} width - used to restrict width of grid..
48603 * @cfg {Number} height - used to restrict height of grid..
48607 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48613 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48614 * {tag: "input", type: "checkbox", autocomplete: "off"})
48616 // defaultAutoCreate : { tag: 'div' },
48617 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48619 * @cfg {String} addTitle Text to include for adding a title.
48623 onResize : function(){
48624 Roo.form.Field.superclass.onResize.apply(this, arguments);
48627 initEvents : function(){
48628 // Roo.form.Checkbox.superclass.initEvents.call(this);
48629 // has no events...
48634 getResizeEl : function(){
48638 getPositionEl : function(){
48643 onRender : function(ct, position){
48645 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48646 var style = this.style;
48649 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48650 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48651 this.viewEl = this.wrap.createChild({ tag: 'div' });
48653 this.viewEl.applyStyles(style);
48656 this.viewEl.setWidth(this.width);
48659 this.viewEl.setHeight(this.height);
48661 //if(this.inputValue !== undefined){
48662 //this.setValue(this.value);
48665 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48668 this.grid.render();
48669 this.grid.getDataSource().on('remove', this.refreshValue, this);
48670 this.grid.getDataSource().on('update', this.refreshValue, this);
48671 this.grid.on('afteredit', this.refreshValue, this);
48677 * Sets the value of the item.
48678 * @param {String} either an object or a string..
48680 setValue : function(v){
48682 v = v || []; // empty set..
48683 // this does not seem smart - it really only affects memoryproxy grids..
48684 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48685 var ds = this.grid.getDataSource();
48686 // assumes a json reader..
48688 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48689 ds.loadData( data);
48691 // clear selection so it does not get stale.
48692 if (this.grid.sm) {
48693 this.grid.sm.clearSelections();
48696 Roo.form.GridField.superclass.setValue.call(this, v);
48697 this.refreshValue();
48698 // should load data in the grid really....
48702 refreshValue: function() {
48704 this.grid.getDataSource().each(function(r) {
48707 this.el.dom.value = Roo.encode(val);
48715 * Ext JS Library 1.1.1
48716 * Copyright(c) 2006-2007, Ext JS, LLC.
48718 * Originally Released Under LGPL - original licence link has changed is not relivant.
48721 * <script type="text/javascript">
48724 * @class Roo.form.DisplayField
48725 * @extends Roo.form.Field
48726 * A generic Field to display non-editable data.
48727 * @cfg {Boolean} closable (true|false) default false
48729 * Creates a new Display Field item.
48730 * @param {Object} config Configuration options
48732 Roo.form.DisplayField = function(config){
48733 Roo.form.DisplayField.superclass.constructor.call(this, config);
48738 * Fires after the click the close btn
48739 * @param {Roo.form.DisplayField} this
48745 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48746 inputType: 'hidden',
48752 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48754 focusClass : undefined,
48756 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48758 fieldClass: 'x-form-field',
48761 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48763 valueRenderer: undefined,
48767 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48768 * {tag: "input", type: "checkbox", autocomplete: "off"})
48771 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48775 onResize : function(){
48776 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48780 initEvents : function(){
48781 // Roo.form.Checkbox.superclass.initEvents.call(this);
48782 // has no events...
48785 this.closeEl.on('click', this.onClose, this);
48791 getResizeEl : function(){
48795 getPositionEl : function(){
48800 onRender : function(ct, position){
48802 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48803 //if(this.inputValue !== undefined){
48804 this.wrap = this.el.wrap();
48806 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48809 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48812 if (this.bodyStyle) {
48813 this.viewEl.applyStyles(this.bodyStyle);
48815 //this.viewEl.setStyle('padding', '2px');
48817 this.setValue(this.value);
48822 initValue : Roo.emptyFn,
48827 onClick : function(){
48832 * Sets the checked state of the checkbox.
48833 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48835 setValue : function(v){
48837 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48838 // this might be called before we have a dom element..
48839 if (!this.viewEl) {
48842 this.viewEl.dom.innerHTML = html;
48843 Roo.form.DisplayField.superclass.setValue.call(this, v);
48847 onClose : function(e)
48849 e.preventDefault();
48851 this.fireEvent('close', this);
48860 * @class Roo.form.DayPicker
48861 * @extends Roo.form.Field
48862 * A Day picker show [M] [T] [W] ....
48864 * Creates a new Day Picker
48865 * @param {Object} config Configuration options
48867 Roo.form.DayPicker= function(config){
48868 Roo.form.DayPicker.superclass.constructor.call(this, config);
48872 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
48874 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48876 focusClass : undefined,
48878 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48880 fieldClass: "x-form-field",
48883 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48884 * {tag: "input", type: "checkbox", autocomplete: "off"})
48886 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
48889 actionMode : 'viewEl',
48893 inputType : 'hidden',
48896 inputElement: false, // real input element?
48897 basedOn: false, // ????
48899 isFormField: true, // not sure where this is needed!!!!
48901 onResize : function(){
48902 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
48903 if(!this.boxLabel){
48904 this.el.alignTo(this.wrap, 'c-c');
48908 initEvents : function(){
48909 Roo.form.Checkbox.superclass.initEvents.call(this);
48910 this.el.on("click", this.onClick, this);
48911 this.el.on("change", this.onClick, this);
48915 getResizeEl : function(){
48919 getPositionEl : function(){
48925 onRender : function(ct, position){
48926 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
48928 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
48930 var r1 = '<table><tr>';
48931 var r2 = '<tr class="x-form-daypick-icons">';
48932 for (var i=0; i < 7; i++) {
48933 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
48934 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
48937 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
48938 viewEl.select('img').on('click', this.onClick, this);
48939 this.viewEl = viewEl;
48942 // this will not work on Chrome!!!
48943 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
48944 this.el.on('propertychange', this.setFromHidden, this); //ie
48952 initValue : Roo.emptyFn,
48955 * Returns the checked state of the checkbox.
48956 * @return {Boolean} True if checked, else false
48958 getValue : function(){
48959 return this.el.dom.value;
48964 onClick : function(e){
48965 //this.setChecked(!this.checked);
48966 Roo.get(e.target).toggleClass('x-menu-item-checked');
48967 this.refreshValue();
48968 //if(this.el.dom.checked != this.checked){
48969 // this.setValue(this.el.dom.checked);
48974 refreshValue : function()
48977 this.viewEl.select('img',true).each(function(e,i,n) {
48978 val += e.is(".x-menu-item-checked") ? String(n) : '';
48980 this.setValue(val, true);
48984 * Sets the checked state of the checkbox.
48985 * On is always based on a string comparison between inputValue and the param.
48986 * @param {Boolean/String} value - the value to set
48987 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
48989 setValue : function(v,suppressEvent){
48990 if (!this.el.dom) {
48993 var old = this.el.dom.value ;
48994 this.el.dom.value = v;
48995 if (suppressEvent) {
48999 // update display..
49000 this.viewEl.select('img',true).each(function(e,i,n) {
49002 var on = e.is(".x-menu-item-checked");
49003 var newv = v.indexOf(String(n)) > -1;
49005 e.toggleClass('x-menu-item-checked');
49011 this.fireEvent('change', this, v, old);
49016 // handle setting of hidden value by some other method!!?!?
49017 setFromHidden: function()
49022 //console.log("SET FROM HIDDEN");
49023 //alert('setFrom hidden');
49024 this.setValue(this.el.dom.value);
49027 onDestroy : function()
49030 Roo.get(this.viewEl).remove();
49033 Roo.form.DayPicker.superclass.onDestroy.call(this);
49037 * RooJS Library 1.1.1
49038 * Copyright(c) 2008-2011 Alan Knowles
49045 * @class Roo.form.ComboCheck
49046 * @extends Roo.form.ComboBox
49047 * A combobox for multiple select items.
49049 * FIXME - could do with a reset button..
49052 * Create a new ComboCheck
49053 * @param {Object} config Configuration options
49055 Roo.form.ComboCheck = function(config){
49056 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49057 // should verify some data...
49059 // hiddenName = required..
49060 // displayField = required
49061 // valudField == required
49062 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49064 Roo.each(req, function(e) {
49065 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49066 throw "Roo.form.ComboCheck : missing value for: " + e;
49073 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49078 selectedClass: 'x-menu-item-checked',
49081 onRender : function(ct, position){
49087 var cls = 'x-combo-list';
49090 this.tpl = new Roo.Template({
49091 html : '<div class="'+cls+'-item x-menu-check-item">' +
49092 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49093 '<span>{' + this.displayField + '}</span>' +
49100 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49101 this.view.singleSelect = false;
49102 this.view.multiSelect = true;
49103 this.view.toggleSelect = true;
49104 this.pageTb.add(new Roo.Toolbar.Fill(), {
49107 handler: function()
49114 onViewOver : function(e, t){
49120 onViewClick : function(doFocus,index){
49124 select: function () {
49125 //Roo.log("SELECT CALLED");
49128 selectByValue : function(xv, scrollIntoView){
49129 var ar = this.getValueArray();
49132 Roo.each(ar, function(v) {
49133 if(v === undefined || v === null){
49136 var r = this.findRecord(this.valueField, v);
49138 sels.push(this.store.indexOf(r))
49142 this.view.select(sels);
49148 onSelect : function(record, index){
49149 // Roo.log("onselect Called");
49150 // this is only called by the clear button now..
49151 this.view.clearSelections();
49152 this.setValue('[]');
49153 if (this.value != this.valueBefore) {
49154 this.fireEvent('change', this, this.value, this.valueBefore);
49155 this.valueBefore = this.value;
49158 getValueArray : function()
49163 //Roo.log(this.value);
49164 if (typeof(this.value) == 'undefined') {
49167 var ar = Roo.decode(this.value);
49168 return ar instanceof Array ? ar : []; //?? valid?
49171 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49176 expand : function ()
49179 Roo.form.ComboCheck.superclass.expand.call(this);
49180 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49181 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49186 collapse : function(){
49187 Roo.form.ComboCheck.superclass.collapse.call(this);
49188 var sl = this.view.getSelectedIndexes();
49189 var st = this.store;
49193 Roo.each(sl, function(i) {
49195 nv.push(r.get(this.valueField));
49197 this.setValue(Roo.encode(nv));
49198 if (this.value != this.valueBefore) {
49200 this.fireEvent('change', this, this.value, this.valueBefore);
49201 this.valueBefore = this.value;
49206 setValue : function(v){
49210 var vals = this.getValueArray();
49212 Roo.each(vals, function(k) {
49213 var r = this.findRecord(this.valueField, k);
49215 tv.push(r.data[this.displayField]);
49216 }else if(this.valueNotFoundText !== undefined){
49217 tv.push( this.valueNotFoundText );
49222 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49223 this.hiddenField.value = v;
49229 * Ext JS Library 1.1.1
49230 * Copyright(c) 2006-2007, Ext JS, LLC.
49232 * Originally Released Under LGPL - original licence link has changed is not relivant.
49235 * <script type="text/javascript">
49239 * @class Roo.form.Signature
49240 * @extends Roo.form.Field
49244 * @param {Object} config Configuration options
49247 Roo.form.Signature = function(config){
49248 Roo.form.Signature.superclass.constructor.call(this, config);
49250 this.addEvents({// not in used??
49253 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49254 * @param {Roo.form.Signature} combo This combo box
49259 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49260 * @param {Roo.form.ComboBox} combo This combo box
49261 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49267 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49269 * @cfg {Object} labels Label to use when rendering a form.
49273 * confirm : "Confirm"
49278 confirm : "Confirm"
49281 * @cfg {Number} width The signature panel width (defaults to 300)
49285 * @cfg {Number} height The signature panel height (defaults to 100)
49289 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49291 allowBlank : false,
49294 // {Object} signPanel The signature SVG panel element (defaults to {})
49296 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49297 isMouseDown : false,
49298 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49299 isConfirmed : false,
49300 // {String} signatureTmp SVG mapping string (defaults to empty string)
49304 defaultAutoCreate : { // modified by initCompnoent..
49310 onRender : function(ct, position){
49312 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49314 this.wrap = this.el.wrap({
49315 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49318 this.createToolbar(this);
49319 this.signPanel = this.wrap.createChild({
49321 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49325 this.svgID = Roo.id();
49326 this.svgEl = this.signPanel.createChild({
49327 xmlns : 'http://www.w3.org/2000/svg',
49329 id : this.svgID + "-svg",
49331 height: this.height,
49332 viewBox: '0 0 '+this.width+' '+this.height,
49336 id: this.svgID + "-svg-r",
49338 height: this.height,
49343 id: this.svgID + "-svg-l",
49345 y1: (this.height*0.8), // start set the line in 80% of height
49346 x2: this.width, // end
49347 y2: (this.height*0.8), // end set the line in 80% of height
49349 'stroke-width': "1",
49350 'stroke-dasharray': "3",
49351 'shape-rendering': "crispEdges",
49352 'pointer-events': "none"
49356 id: this.svgID + "-svg-p",
49358 'stroke-width': "3",
49360 'pointer-events': 'none'
49365 this.svgBox = this.svgEl.dom.getScreenCTM();
49367 createSVG : function(){
49368 var svg = this.signPanel;
49369 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49372 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49373 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49374 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49375 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49376 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49377 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49378 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49381 isTouchEvent : function(e){
49382 return e.type.match(/^touch/);
49384 getCoords : function (e) {
49385 var pt = this.svgEl.dom.createSVGPoint();
49388 if (this.isTouchEvent(e)) {
49389 pt.x = e.targetTouches[0].clientX;
49390 pt.y = e.targetTouches[0].clientY;
49392 var a = this.svgEl.dom.getScreenCTM();
49393 var b = a.inverse();
49394 var mx = pt.matrixTransform(b);
49395 return mx.x + ',' + mx.y;
49397 //mouse event headler
49398 down : function (e) {
49399 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49400 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49402 this.isMouseDown = true;
49404 e.preventDefault();
49406 move : function (e) {
49407 if (this.isMouseDown) {
49408 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49409 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49412 e.preventDefault();
49414 up : function (e) {
49415 this.isMouseDown = false;
49416 var sp = this.signatureTmp.split(' ');
49419 if(!sp[sp.length-2].match(/^L/)){
49423 this.signatureTmp = sp.join(" ");
49426 if(this.getValue() != this.signatureTmp){
49427 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49428 this.isConfirmed = false;
49430 e.preventDefault();
49434 * Protected method that will not generally be called directly. It
49435 * is called when the editor creates its toolbar. Override this method if you need to
49436 * add custom toolbar buttons.
49437 * @param {HtmlEditor} editor
49439 createToolbar : function(editor){
49440 function btn(id, toggle, handler){
49441 var xid = fid + '-'+ id ;
49445 cls : 'x-btn-icon x-edit-'+id,
49446 enableToggle:toggle !== false,
49447 scope: editor, // was editor...
49448 handler:handler||editor.relayBtnCmd,
49449 clickEvent:'mousedown',
49450 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49456 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49460 cls : ' x-signature-btn x-signature-'+id,
49461 scope: editor, // was editor...
49462 handler: this.reset,
49463 clickEvent:'mousedown',
49464 text: this.labels.clear
49471 cls : ' x-signature-btn x-signature-'+id,
49472 scope: editor, // was editor...
49473 handler: this.confirmHandler,
49474 clickEvent:'mousedown',
49475 text: this.labels.confirm
49482 * when user is clicked confirm then show this image.....
49484 * @return {String} Image Data URI
49486 getImageDataURI : function(){
49487 var svg = this.svgEl.dom.parentNode.innerHTML;
49488 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49493 * @return {Boolean} this.isConfirmed
49495 getConfirmed : function(){
49496 return this.isConfirmed;
49500 * @return {Number} this.width
49502 getWidth : function(){
49507 * @return {Number} this.height
49509 getHeight : function(){
49510 return this.height;
49513 getSignature : function(){
49514 return this.signatureTmp;
49517 reset : function(){
49518 this.signatureTmp = '';
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', '');
49521 this.isConfirmed = false;
49522 Roo.form.Signature.superclass.reset.call(this);
49524 setSignature : function(s){
49525 this.signatureTmp = s;
49526 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49527 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49529 this.isConfirmed = false;
49530 Roo.form.Signature.superclass.reset.call(this);
49533 // Roo.log(this.signPanel.dom.contentWindow.up())
49536 setConfirmed : function(){
49540 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49543 confirmHandler : function(){
49544 if(!this.getSignature()){
49548 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49549 this.setValue(this.getSignature());
49550 this.isConfirmed = true;
49552 this.fireEvent('confirm', this);
49555 // Subclasses should provide the validation implementation by overriding this
49556 validateValue : function(value){
49557 if(this.allowBlank){
49561 if(this.isConfirmed){
49568 * Ext JS Library 1.1.1
49569 * Copyright(c) 2006-2007, Ext JS, LLC.
49571 * Originally Released Under LGPL - original licence link has changed is not relivant.
49574 * <script type="text/javascript">
49579 * @class Roo.form.ComboBox
49580 * @extends Roo.form.TriggerField
49581 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49583 * Create a new ComboBox.
49584 * @param {Object} config Configuration options
49586 Roo.form.Select = function(config){
49587 Roo.form.Select.superclass.constructor.call(this, config);
49591 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49593 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49596 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49597 * rendering into an Roo.Editor, defaults to false)
49600 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49601 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49604 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49607 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49608 * the dropdown list (defaults to undefined, with no header element)
49612 * @cfg {String/Roo.Template} tpl The template to use to render the output
49616 defaultAutoCreate : {tag: "select" },
49618 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49620 listWidth: undefined,
49622 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49623 * mode = 'remote' or 'text' if mode = 'local')
49625 displayField: undefined,
49627 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49628 * mode = 'remote' or 'value' if mode = 'local').
49629 * Note: use of a valueField requires the user make a selection
49630 * in order for a value to be mapped.
49632 valueField: undefined,
49636 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49637 * field's data value (defaults to the underlying DOM element's name)
49639 hiddenName: undefined,
49641 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49645 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49647 selectedClass: 'x-combo-selected',
49649 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49650 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49651 * which displays a downward arrow icon).
49653 triggerClass : 'x-form-arrow-trigger',
49655 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49659 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49660 * anchor positions (defaults to 'tl-bl')
49662 listAlign: 'tl-bl?',
49664 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49668 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49669 * query specified by the allQuery config option (defaults to 'query')
49671 triggerAction: 'query',
49673 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49674 * (defaults to 4, does not apply if editable = false)
49678 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49679 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49683 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49684 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49688 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49689 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49693 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49694 * when editable = true (defaults to false)
49696 selectOnFocus:false,
49698 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49700 queryParam: 'query',
49702 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49703 * when mode = 'remote' (defaults to 'Loading...')
49705 loadingText: 'Loading...',
49707 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49711 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49715 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49716 * traditional select (defaults to true)
49720 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49724 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49728 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49729 * listWidth has a higher value)
49733 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49734 * allow the user to set arbitrary text into the field (defaults to false)
49736 forceSelection:false,
49738 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49739 * if typeAhead = true (defaults to 250)
49741 typeAheadDelay : 250,
49743 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49744 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49746 valueNotFoundText : undefined,
49749 * @cfg {String} defaultValue The value displayed after loading the store.
49754 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49756 blockFocus : false,
49759 * @cfg {Boolean} disableClear Disable showing of clear button.
49761 disableClear : false,
49763 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49765 alwaysQuery : false,
49771 // element that contains real text value.. (when hidden is used..)
49774 onRender : function(ct, position){
49775 Roo.form.Field.prototype.onRender.call(this, ct, position);
49778 this.store.on('beforeload', this.onBeforeLoad, this);
49779 this.store.on('load', this.onLoad, this);
49780 this.store.on('loadexception', this.onLoadException, this);
49781 this.store.load({});
49789 initEvents : function(){
49790 //Roo.form.ComboBox.superclass.initEvents.call(this);
49794 onDestroy : function(){
49797 this.store.un('beforeload', this.onBeforeLoad, this);
49798 this.store.un('load', this.onLoad, this);
49799 this.store.un('loadexception', this.onLoadException, this);
49801 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49805 fireKey : function(e){
49806 if(e.isNavKeyPress() && !this.list.isVisible()){
49807 this.fireEvent("specialkey", this, e);
49812 onResize: function(w, h){
49820 * Allow or prevent the user from directly editing the field text. If false is passed,
49821 * the user will only be able to select from the items defined in the dropdown list. This method
49822 * is the runtime equivalent of setting the 'editable' config option at config time.
49823 * @param {Boolean} value True to allow the user to directly edit the field text
49825 setEditable : function(value){
49830 onBeforeLoad : function(){
49832 Roo.log("Select before load");
49835 this.innerList.update(this.loadingText ?
49836 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49837 //this.restrictHeight();
49838 this.selectedIndex = -1;
49842 onLoad : function(){
49845 var dom = this.el.dom;
49846 dom.innerHTML = '';
49847 var od = dom.ownerDocument;
49849 if (this.emptyText) {
49850 var op = od.createElement('option');
49851 op.setAttribute('value', '');
49852 op.innerHTML = String.format('{0}', this.emptyText);
49853 dom.appendChild(op);
49855 if(this.store.getCount() > 0){
49857 var vf = this.valueField;
49858 var df = this.displayField;
49859 this.store.data.each(function(r) {
49860 // which colmsn to use... testing - cdoe / title..
49861 var op = od.createElement('option');
49862 op.setAttribute('value', r.data[vf]);
49863 op.innerHTML = String.format('{0}', r.data[df]);
49864 dom.appendChild(op);
49866 if (typeof(this.defaultValue != 'undefined')) {
49867 this.setValue(this.defaultValue);
49872 //this.onEmptyResults();
49877 onLoadException : function()
49879 dom.innerHTML = '';
49881 Roo.log("Select on load exception");
49885 Roo.log(this.store.reader.jsonData);
49886 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
49887 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
49893 onTypeAhead : function(){
49898 onSelect : function(record, index){
49899 Roo.log('on select?');
49901 if(this.fireEvent('beforeselect', this, record, index) !== false){
49902 this.setFromData(index > -1 ? record.data : false);
49904 this.fireEvent('select', this, record, index);
49909 * Returns the currently selected field value or empty string if no value is set.
49910 * @return {String} value The selected value
49912 getValue : function(){
49913 var dom = this.el.dom;
49914 this.value = dom.options[dom.selectedIndex].value;
49920 * Clears any text/value currently set in the field
49922 clearValue : function(){
49924 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
49929 * Sets the specified value into the field. If the value finds a match, the corresponding record text
49930 * will be displayed in the field. If the value does not match the data value of an existing item,
49931 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
49932 * Otherwise the field will be blank (although the value will still be set).
49933 * @param {String} value The value to match
49935 setValue : function(v){
49936 var d = this.el.dom;
49937 for (var i =0; i < d.options.length;i++) {
49938 if (v == d.options[i].value) {
49939 d.selectedIndex = i;
49947 * @property {Object} the last set data for the element
49952 * Sets the value of the field based on a object which is related to the record format for the store.
49953 * @param {Object} value the value to set as. or false on reset?
49955 setFromData : function(o){
49956 Roo.log('setfrom data?');
49962 reset : function(){
49966 findRecord : function(prop, value){
49971 if(this.store.getCount() > 0){
49972 this.store.each(function(r){
49973 if(r.data[prop] == value){
49983 getName: function()
49985 // returns hidden if it's set..
49986 if (!this.rendered) {return ''};
49987 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
49995 onEmptyResults : function(){
49996 Roo.log('empty results');
50001 * Returns true if the dropdown list is expanded, else false.
50003 isExpanded : function(){
50008 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50009 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50010 * @param {String} value The data value of the item to select
50011 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50012 * selected item if it is not currently in view (defaults to true)
50013 * @return {Boolean} True if the value matched an item in the list, else false
50015 selectByValue : function(v, scrollIntoView){
50016 Roo.log('select By Value');
50019 if(v !== undefined && v !== null){
50020 var r = this.findRecord(this.valueField || this.displayField, v);
50022 this.select(this.store.indexOf(r), scrollIntoView);
50030 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50031 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50032 * @param {Number} index The zero-based index of the list item to select
50033 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50034 * selected item if it is not currently in view (defaults to true)
50036 select : function(index, scrollIntoView){
50037 Roo.log('select ');
50040 this.selectedIndex = index;
50041 this.view.select(index);
50042 if(scrollIntoView !== false){
50043 var el = this.view.getNode(index);
50045 this.innerList.scrollChildIntoView(el, false);
50053 validateBlur : function(){
50060 initQuery : function(){
50061 this.doQuery(this.getRawValue());
50065 doForce : function(){
50066 if(this.el.dom.value.length > 0){
50067 this.el.dom.value =
50068 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50074 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50075 * query allowing the query action to be canceled if needed.
50076 * @param {String} query The SQL query to execute
50077 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50078 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50079 * saved in the current store (defaults to false)
50081 doQuery : function(q, forceAll){
50083 Roo.log('doQuery?');
50084 if(q === undefined || q === null){
50089 forceAll: forceAll,
50093 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50097 forceAll = qe.forceAll;
50098 if(forceAll === true || (q.length >= this.minChars)){
50099 if(this.lastQuery != q || this.alwaysQuery){
50100 this.lastQuery = q;
50101 if(this.mode == 'local'){
50102 this.selectedIndex = -1;
50104 this.store.clearFilter();
50106 this.store.filter(this.displayField, q);
50110 this.store.baseParams[this.queryParam] = q;
50112 params: this.getParams(q)
50117 this.selectedIndex = -1;
50124 getParams : function(q){
50126 //p[this.queryParam] = q;
50129 p.limit = this.pageSize;
50135 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50137 collapse : function(){
50142 collapseIf : function(e){
50147 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50149 expand : function(){
50157 * @cfg {Boolean} grow
50161 * @cfg {Number} growMin
50165 * @cfg {Number} growMax
50173 setWidth : function()
50177 getResizeEl : function(){
50180 });//<script type="text/javasscript">
50184 * @class Roo.DDView
50185 * A DnD enabled version of Roo.View.
50186 * @param {Element/String} container The Element in which to create the View.
50187 * @param {String} tpl The template string used to create the markup for each element of the View
50188 * @param {Object} config The configuration properties. These include all the config options of
50189 * {@link Roo.View} plus some specific to this class.<br>
50191 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50192 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50194 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50195 .x-view-drag-insert-above {
50196 border-top:1px dotted #3366cc;
50198 .x-view-drag-insert-below {
50199 border-bottom:1px dotted #3366cc;
50205 Roo.DDView = function(container, tpl, config) {
50206 Roo.DDView.superclass.constructor.apply(this, arguments);
50207 this.getEl().setStyle("outline", "0px none");
50208 this.getEl().unselectable();
50209 if (this.dragGroup) {
50210 this.setDraggable(this.dragGroup.split(","));
50212 if (this.dropGroup) {
50213 this.setDroppable(this.dropGroup.split(","));
50215 if (this.deletable) {
50216 this.setDeletable();
50218 this.isDirtyFlag = false;
50224 Roo.extend(Roo.DDView, Roo.View, {
50225 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50226 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50227 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50228 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50232 reset: Roo.emptyFn,
50234 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50236 validate: function() {
50240 destroy: function() {
50241 this.purgeListeners();
50242 this.getEl.removeAllListeners();
50243 this.getEl().remove();
50244 if (this.dragZone) {
50245 if (this.dragZone.destroy) {
50246 this.dragZone.destroy();
50249 if (this.dropZone) {
50250 if (this.dropZone.destroy) {
50251 this.dropZone.destroy();
50256 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50257 getName: function() {
50261 /** Loads the View from a JSON string representing the Records to put into the Store. */
50262 setValue: function(v) {
50264 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50267 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50268 this.store.proxy = new Roo.data.MemoryProxy(data);
50272 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50273 getValue: function() {
50275 this.store.each(function(rec) {
50276 result += rec.id + ',';
50278 return result.substr(0, result.length - 1) + ')';
50281 getIds: function() {
50282 var i = 0, result = new Array(this.store.getCount());
50283 this.store.each(function(rec) {
50284 result[i++] = rec.id;
50289 isDirty: function() {
50290 return this.isDirtyFlag;
50294 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50295 * whole Element becomes the target, and this causes the drop gesture to append.
50297 getTargetFromEvent : function(e) {
50298 var target = e.getTarget();
50299 while ((target !== null) && (target.parentNode != this.el.dom)) {
50300 target = target.parentNode;
50303 target = this.el.dom.lastChild || this.el.dom;
50309 * Create the drag data which consists of an object which has the property "ddel" as
50310 * the drag proxy element.
50312 getDragData : function(e) {
50313 var target = this.findItemFromChild(e.getTarget());
50315 this.handleSelection(e);
50316 var selNodes = this.getSelectedNodes();
50319 copy: this.copy || (this.allowCopy && e.ctrlKey),
50323 var selectedIndices = this.getSelectedIndexes();
50324 for (var i = 0; i < selectedIndices.length; i++) {
50325 dragData.records.push(this.store.getAt(selectedIndices[i]));
50327 if (selNodes.length == 1) {
50328 dragData.ddel = target.cloneNode(true); // the div element
50330 var div = document.createElement('div'); // create the multi element drag "ghost"
50331 div.className = 'multi-proxy';
50332 for (var i = 0, len = selNodes.length; i < len; i++) {
50333 div.appendChild(selNodes[i].cloneNode(true));
50335 dragData.ddel = div;
50337 //console.log(dragData)
50338 //console.log(dragData.ddel.innerHTML)
50341 //console.log('nodragData')
50345 /** Specify to which ddGroup items in this DDView may be dragged. */
50346 setDraggable: function(ddGroup) {
50347 if (ddGroup instanceof Array) {
50348 Roo.each(ddGroup, this.setDraggable, this);
50351 if (this.dragZone) {
50352 this.dragZone.addToGroup(ddGroup);
50354 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50355 containerScroll: true,
50359 // Draggability implies selection. DragZone's mousedown selects the element.
50360 if (!this.multiSelect) { this.singleSelect = true; }
50362 // Wire the DragZone's handlers up to methods in *this*
50363 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50367 /** Specify from which ddGroup this DDView accepts drops. */
50368 setDroppable: function(ddGroup) {
50369 if (ddGroup instanceof Array) {
50370 Roo.each(ddGroup, this.setDroppable, this);
50373 if (this.dropZone) {
50374 this.dropZone.addToGroup(ddGroup);
50376 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50377 containerScroll: true,
50381 // Wire the DropZone's handlers up to methods in *this*
50382 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50383 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50384 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50385 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50386 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50390 /** Decide whether to drop above or below a View node. */
50391 getDropPoint : function(e, n, dd){
50392 if (n == this.el.dom) { return "above"; }
50393 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50394 var c = t + (b - t) / 2;
50395 var y = Roo.lib.Event.getPageY(e);
50403 onNodeEnter : function(n, dd, e, data){
50407 onNodeOver : function(n, dd, e, data){
50408 var pt = this.getDropPoint(e, n, dd);
50409 // set the insert point style on the target node
50410 var dragElClass = this.dropNotAllowed;
50413 if (pt == "above"){
50414 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50415 targetElClass = "x-view-drag-insert-above";
50417 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50418 targetElClass = "x-view-drag-insert-below";
50420 if (this.lastInsertClass != targetElClass){
50421 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50422 this.lastInsertClass = targetElClass;
50425 return dragElClass;
50428 onNodeOut : function(n, dd, e, data){
50429 this.removeDropIndicators(n);
50432 onNodeDrop : function(n, dd, e, data){
50433 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50436 var pt = this.getDropPoint(e, n, dd);
50437 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50438 if (pt == "below") { insertAt++; }
50439 for (var i = 0; i < data.records.length; i++) {
50440 var r = data.records[i];
50441 var dup = this.store.getById(r.id);
50442 if (dup && (dd != this.dragZone)) {
50443 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50446 this.store.insert(insertAt++, r.copy());
50448 data.source.isDirtyFlag = true;
50450 this.store.insert(insertAt++, r);
50452 this.isDirtyFlag = true;
50455 this.dragZone.cachedTarget = null;
50459 removeDropIndicators : function(n){
50461 Roo.fly(n).removeClass([
50462 "x-view-drag-insert-above",
50463 "x-view-drag-insert-below"]);
50464 this.lastInsertClass = "_noclass";
50469 * Utility method. Add a delete option to the DDView's context menu.
50470 * @param {String} imageUrl The URL of the "delete" icon image.
50472 setDeletable: function(imageUrl) {
50473 if (!this.singleSelect && !this.multiSelect) {
50474 this.singleSelect = true;
50476 var c = this.getContextMenu();
50477 this.contextMenu.on("itemclick", function(item) {
50480 this.remove(this.getSelectedIndexes());
50484 this.contextMenu.add({
50491 /** Return the context menu for this DDView. */
50492 getContextMenu: function() {
50493 if (!this.contextMenu) {
50494 // Create the View's context menu
50495 this.contextMenu = new Roo.menu.Menu({
50496 id: this.id + "-contextmenu"
50498 this.el.on("contextmenu", this.showContextMenu, this);
50500 return this.contextMenu;
50503 disableContextMenu: function() {
50504 if (this.contextMenu) {
50505 this.el.un("contextmenu", this.showContextMenu, this);
50509 showContextMenu: function(e, item) {
50510 item = this.findItemFromChild(e.getTarget());
50513 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50514 this.contextMenu.showAt(e.getXY());
50519 * Remove {@link Roo.data.Record}s at the specified indices.
50520 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50522 remove: function(selectedIndices) {
50523 selectedIndices = [].concat(selectedIndices);
50524 for (var i = 0; i < selectedIndices.length; i++) {
50525 var rec = this.store.getAt(selectedIndices[i]);
50526 this.store.remove(rec);
50531 * Double click fires the event, but also, if this is draggable, and there is only one other
50532 * related DropZone, it transfers the selected node.
50534 onDblClick : function(e){
50535 var item = this.findItemFromChild(e.getTarget());
50537 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50540 if (this.dragGroup) {
50541 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50542 while (targets.indexOf(this.dropZone) > -1) {
50543 targets.remove(this.dropZone);
50545 if (targets.length == 1) {
50546 this.dragZone.cachedTarget = null;
50547 var el = Roo.get(targets[0].getEl());
50548 var box = el.getBox(true);
50549 targets[0].onNodeDrop(el.dom, {
50551 xy: [box.x, box.y + box.height - 1]
50552 }, null, this.getDragData(e));
50558 handleSelection: function(e) {
50559 this.dragZone.cachedTarget = null;
50560 var item = this.findItemFromChild(e.getTarget());
50562 this.clearSelections(true);
50565 if (item && (this.multiSelect || this.singleSelect)){
50566 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50567 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50568 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50569 this.unselect(item);
50571 this.select(item, this.multiSelect && e.ctrlKey);
50572 this.lastSelection = item;
50577 onItemClick : function(item, index, e){
50578 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50584 unselect : function(nodeInfo, suppressEvent){
50585 var node = this.getNode(nodeInfo);
50586 if(node && this.isSelected(node)){
50587 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50588 Roo.fly(node).removeClass(this.selectedClass);
50589 this.selections.remove(node);
50590 if(!suppressEvent){
50591 this.fireEvent("selectionchange", this, this.selections);
50599 * Ext JS Library 1.1.1
50600 * Copyright(c) 2006-2007, Ext JS, LLC.
50602 * Originally Released Under LGPL - original licence link has changed is not relivant.
50605 * <script type="text/javascript">
50609 * @class Roo.LayoutManager
50610 * @extends Roo.util.Observable
50611 * Base class for layout managers.
50613 Roo.LayoutManager = function(container, config){
50614 Roo.LayoutManager.superclass.constructor.call(this);
50615 this.el = Roo.get(container);
50616 // ie scrollbar fix
50617 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50618 document.body.scroll = "no";
50619 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50620 this.el.position('relative');
50622 this.id = this.el.id;
50623 this.el.addClass("x-layout-container");
50624 /** false to disable window resize monitoring @type Boolean */
50625 this.monitorWindowResize = true;
50630 * Fires when a layout is performed.
50631 * @param {Roo.LayoutManager} this
50635 * @event regionresized
50636 * Fires when the user resizes a region.
50637 * @param {Roo.LayoutRegion} region The resized region
50638 * @param {Number} newSize The new size (width for east/west, height for north/south)
50640 "regionresized" : true,
50642 * @event regioncollapsed
50643 * Fires when a region is collapsed.
50644 * @param {Roo.LayoutRegion} region The collapsed region
50646 "regioncollapsed" : true,
50648 * @event regionexpanded
50649 * Fires when a region is expanded.
50650 * @param {Roo.LayoutRegion} region The expanded region
50652 "regionexpanded" : true
50654 this.updating = false;
50655 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50658 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50660 * Returns true if this layout is currently being updated
50661 * @return {Boolean}
50663 isUpdating : function(){
50664 return this.updating;
50668 * Suspend the LayoutManager from doing auto-layouts while
50669 * making multiple add or remove calls
50671 beginUpdate : function(){
50672 this.updating = true;
50676 * Restore auto-layouts and optionally disable the manager from performing a layout
50677 * @param {Boolean} noLayout true to disable a layout update
50679 endUpdate : function(noLayout){
50680 this.updating = false;
50686 layout: function(){
50690 onRegionResized : function(region, newSize){
50691 this.fireEvent("regionresized", region, newSize);
50695 onRegionCollapsed : function(region){
50696 this.fireEvent("regioncollapsed", region);
50699 onRegionExpanded : function(region){
50700 this.fireEvent("regionexpanded", region);
50704 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50705 * performs box-model adjustments.
50706 * @return {Object} The size as an object {width: (the width), height: (the height)}
50708 getViewSize : function(){
50710 if(this.el.dom != document.body){
50711 size = this.el.getSize();
50713 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50715 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50716 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50721 * Returns the Element this layout is bound to.
50722 * @return {Roo.Element}
50724 getEl : function(){
50729 * Returns the specified region.
50730 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50731 * @return {Roo.LayoutRegion}
50733 getRegion : function(target){
50734 return this.regions[target.toLowerCase()];
50737 onWindowResize : function(){
50738 if(this.monitorWindowResize){
50744 * Ext JS Library 1.1.1
50745 * Copyright(c) 2006-2007, Ext JS, LLC.
50747 * Originally Released Under LGPL - original licence link has changed is not relivant.
50750 * <script type="text/javascript">
50753 * @class Roo.BorderLayout
50754 * @extends Roo.LayoutManager
50755 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50756 * please see: <br><br>
50757 * <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>
50758 * <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>
50761 var layout = new Roo.BorderLayout(document.body, {
50795 preferredTabWidth: 150
50800 var CP = Roo.ContentPanel;
50802 layout.beginUpdate();
50803 layout.add("north", new CP("north", "North"));
50804 layout.add("south", new CP("south", {title: "South", closable: true}));
50805 layout.add("west", new CP("west", {title: "West"}));
50806 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50807 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50808 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50809 layout.getRegion("center").showPanel("center1");
50810 layout.endUpdate();
50813 <b>The container the layout is rendered into can be either the body element or any other element.
50814 If it is not the body element, the container needs to either be an absolute positioned element,
50815 or you will need to add "position:relative" to the css of the container. You will also need to specify
50816 the container size if it is not the body element.</b>
50819 * Create a new BorderLayout
50820 * @param {String/HTMLElement/Element} container The container this layout is bound to
50821 * @param {Object} config Configuration options
50823 Roo.BorderLayout = function(container, config){
50824 config = config || {};
50825 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50826 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50827 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50828 var target = this.factory.validRegions[i];
50829 if(config[target]){
50830 this.addRegion(target, config[target]);
50835 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50837 * Creates and adds a new region if it doesn't already exist.
50838 * @param {String} target The target region key (north, south, east, west or center).
50839 * @param {Object} config The regions config object
50840 * @return {BorderLayoutRegion} The new region
50842 addRegion : function(target, config){
50843 if(!this.regions[target]){
50844 var r = this.factory.create(target, this, config);
50845 this.bindRegion(target, r);
50847 return this.regions[target];
50851 bindRegion : function(name, r){
50852 this.regions[name] = r;
50853 r.on("visibilitychange", this.layout, this);
50854 r.on("paneladded", this.layout, this);
50855 r.on("panelremoved", this.layout, this);
50856 r.on("invalidated", this.layout, this);
50857 r.on("resized", this.onRegionResized, this);
50858 r.on("collapsed", this.onRegionCollapsed, this);
50859 r.on("expanded", this.onRegionExpanded, this);
50863 * Performs a layout update.
50865 layout : function(){
50866 if(this.updating) {
50869 var size = this.getViewSize();
50870 var w = size.width;
50871 var h = size.height;
50876 //var x = 0, y = 0;
50878 var rs = this.regions;
50879 var north = rs["north"];
50880 var south = rs["south"];
50881 var west = rs["west"];
50882 var east = rs["east"];
50883 var center = rs["center"];
50884 //if(this.hideOnLayout){ // not supported anymore
50885 //c.el.setStyle("display", "none");
50887 if(north && north.isVisible()){
50888 var b = north.getBox();
50889 var m = north.getMargins();
50890 b.width = w - (m.left+m.right);
50893 centerY = b.height + b.y + m.bottom;
50894 centerH -= centerY;
50895 north.updateBox(this.safeBox(b));
50897 if(south && south.isVisible()){
50898 var b = south.getBox();
50899 var m = south.getMargins();
50900 b.width = w - (m.left+m.right);
50902 var totalHeight = (b.height + m.top + m.bottom);
50903 b.y = h - totalHeight + m.top;
50904 centerH -= totalHeight;
50905 south.updateBox(this.safeBox(b));
50907 if(west && west.isVisible()){
50908 var b = west.getBox();
50909 var m = west.getMargins();
50910 b.height = centerH - (m.top+m.bottom);
50912 b.y = centerY + m.top;
50913 var totalWidth = (b.width + m.left + m.right);
50914 centerX += totalWidth;
50915 centerW -= totalWidth;
50916 west.updateBox(this.safeBox(b));
50918 if(east && east.isVisible()){
50919 var b = east.getBox();
50920 var m = east.getMargins();
50921 b.height = centerH - (m.top+m.bottom);
50922 var totalWidth = (b.width + m.left + m.right);
50923 b.x = w - totalWidth + m.left;
50924 b.y = centerY + m.top;
50925 centerW -= totalWidth;
50926 east.updateBox(this.safeBox(b));
50929 var m = center.getMargins();
50931 x: centerX + m.left,
50932 y: centerY + m.top,
50933 width: centerW - (m.left+m.right),
50934 height: centerH - (m.top+m.bottom)
50936 //if(this.hideOnLayout){
50937 //center.el.setStyle("display", "block");
50939 center.updateBox(this.safeBox(centerBox));
50942 this.fireEvent("layout", this);
50946 safeBox : function(box){
50947 box.width = Math.max(0, box.width);
50948 box.height = Math.max(0, box.height);
50953 * Adds a ContentPanel (or subclass) to this layout.
50954 * @param {String} target The target region key (north, south, east, west or center).
50955 * @param {Roo.ContentPanel} panel The panel to add
50956 * @return {Roo.ContentPanel} The added panel
50958 add : function(target, panel){
50960 target = target.toLowerCase();
50961 return this.regions[target].add(panel);
50965 * Remove a ContentPanel (or subclass) to this layout.
50966 * @param {String} target The target region key (north, south, east, west or center).
50967 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
50968 * @return {Roo.ContentPanel} The removed panel
50970 remove : function(target, panel){
50971 target = target.toLowerCase();
50972 return this.regions[target].remove(panel);
50976 * Searches all regions for a panel with the specified id
50977 * @param {String} panelId
50978 * @return {Roo.ContentPanel} The panel or null if it wasn't found
50980 findPanel : function(panelId){
50981 var rs = this.regions;
50982 for(var target in rs){
50983 if(typeof rs[target] != "function"){
50984 var p = rs[target].getPanel(panelId);
50994 * Searches all regions for a panel with the specified id and activates (shows) it.
50995 * @param {String/ContentPanel} panelId The panels id or the panel itself
50996 * @return {Roo.ContentPanel} The shown panel or null
50998 showPanel : function(panelId) {
50999 var rs = this.regions;
51000 for(var target in rs){
51001 var r = rs[target];
51002 if(typeof r != "function"){
51003 if(r.hasPanel(panelId)){
51004 return r.showPanel(panelId);
51012 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51013 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51015 restoreState : function(provider){
51017 provider = Roo.state.Manager;
51019 var sm = new Roo.LayoutStateManager();
51020 sm.init(this, provider);
51024 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51025 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51026 * a valid ContentPanel config object. Example:
51028 // Create the main layout
51029 var layout = new Roo.BorderLayout('main-ct', {
51040 // Create and add multiple ContentPanels at once via configs
51043 id: 'source-files',
51045 title:'Ext Source Files',
51058 * @param {Object} regions An object containing ContentPanel configs by region name
51060 batchAdd : function(regions){
51061 this.beginUpdate();
51062 for(var rname in regions){
51063 var lr = this.regions[rname];
51065 this.addTypedPanels(lr, regions[rname]);
51072 addTypedPanels : function(lr, ps){
51073 if(typeof ps == 'string'){
51074 lr.add(new Roo.ContentPanel(ps));
51076 else if(ps instanceof Array){
51077 for(var i =0, len = ps.length; i < len; i++){
51078 this.addTypedPanels(lr, ps[i]);
51081 else if(!ps.events){ // raw config?
51083 delete ps.el; // prevent conflict
51084 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51086 else { // panel object assumed!
51091 * Adds a xtype elements to the layout.
51095 xtype : 'ContentPanel',
51102 xtype : 'NestedLayoutPanel',
51108 items : [ ... list of content panels or nested layout panels.. ]
51112 * @param {Object} cfg Xtype definition of item to add.
51114 addxtype : function(cfg)
51116 // basically accepts a pannel...
51117 // can accept a layout region..!?!?
51118 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51120 if (!cfg.xtype.match(/Panel$/)) {
51125 if (typeof(cfg.region) == 'undefined') {
51126 Roo.log("Failed to add Panel, region was not set");
51130 var region = cfg.region;
51136 xitems = cfg.items;
51143 case 'ContentPanel': // ContentPanel (el, cfg)
51144 case 'ScrollPanel': // ContentPanel (el, cfg)
51146 if(cfg.autoCreate) {
51147 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51149 var el = this.el.createChild();
51150 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51153 this.add(region, ret);
51157 case 'TreePanel': // our new panel!
51158 cfg.el = this.el.createChild();
51159 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51160 this.add(region, ret);
51163 case 'NestedLayoutPanel':
51164 // create a new Layout (which is a Border Layout...
51165 var el = this.el.createChild();
51166 var clayout = cfg.layout;
51168 clayout.items = clayout.items || [];
51169 // replace this exitems with the clayout ones..
51170 xitems = clayout.items;
51173 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51174 cfg.background = false;
51176 var layout = new Roo.BorderLayout(el, clayout);
51178 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51179 //console.log('adding nested layout panel ' + cfg.toSource());
51180 this.add(region, ret);
51181 nb = {}; /// find first...
51186 // needs grid and region
51188 //var el = this.getRegion(region).el.createChild();
51189 var el = this.el.createChild();
51190 // create the grid first...
51192 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51194 if (region == 'center' && this.active ) {
51195 cfg.background = false;
51197 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51199 this.add(region, ret);
51200 if (cfg.background) {
51201 ret.on('activate', function(gp) {
51202 if (!gp.grid.rendered) {
51217 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51219 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51220 this.add(region, ret);
51223 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51227 // GridPanel (grid, cfg)
51230 this.beginUpdate();
51234 Roo.each(xitems, function(i) {
51235 region = nb && i.region ? i.region : false;
51237 var add = ret.addxtype(i);
51240 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51241 if (!i.background) {
51242 abn[region] = nb[region] ;
51249 // make the last non-background panel active..
51250 //if (nb) { Roo.log(abn); }
51253 for(var r in abn) {
51254 region = this.getRegion(r);
51256 // tried using nb[r], but it does not work..
51258 region.showPanel(abn[r]);
51269 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51270 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51271 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51272 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51275 var CP = Roo.ContentPanel;
51277 var layout = Roo.BorderLayout.create({
51281 panels: [new CP("north", "North")]
51290 panels: [new CP("west", {title: "West"})]
51299 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51308 panels: [new CP("south", {title: "South", closable: true})]
51315 preferredTabWidth: 150,
51317 new CP("center1", {title: "Close Me", closable: true}),
51318 new CP("center2", {title: "Center Panel", closable: false})
51323 layout.getRegion("center").showPanel("center1");
51328 Roo.BorderLayout.create = function(config, targetEl){
51329 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51330 layout.beginUpdate();
51331 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51332 for(var j = 0, jlen = regions.length; j < jlen; j++){
51333 var lr = regions[j];
51334 if(layout.regions[lr] && config[lr].panels){
51335 var r = layout.regions[lr];
51336 var ps = config[lr].panels;
51337 layout.addTypedPanels(r, ps);
51340 layout.endUpdate();
51345 Roo.BorderLayout.RegionFactory = {
51347 validRegions : ["north","south","east","west","center"],
51350 create : function(target, mgr, config){
51351 target = target.toLowerCase();
51352 if(config.lightweight || config.basic){
51353 return new Roo.BasicLayoutRegion(mgr, config, target);
51357 return new Roo.NorthLayoutRegion(mgr, config);
51359 return new Roo.SouthLayoutRegion(mgr, config);
51361 return new Roo.EastLayoutRegion(mgr, config);
51363 return new Roo.WestLayoutRegion(mgr, config);
51365 return new Roo.CenterLayoutRegion(mgr, config);
51367 throw 'Layout region "'+target+'" not supported.';
51371 * Ext JS Library 1.1.1
51372 * Copyright(c) 2006-2007, Ext JS, LLC.
51374 * Originally Released Under LGPL - original licence link has changed is not relivant.
51377 * <script type="text/javascript">
51381 * @class Roo.BasicLayoutRegion
51382 * @extends Roo.util.Observable
51383 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51384 * and does not have a titlebar, tabs or any other features. All it does is size and position
51385 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51387 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51389 this.position = pos;
51392 * @scope Roo.BasicLayoutRegion
51396 * @event beforeremove
51397 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51398 * @param {Roo.LayoutRegion} this
51399 * @param {Roo.ContentPanel} panel The panel
51400 * @param {Object} e The cancel event object
51402 "beforeremove" : true,
51404 * @event invalidated
51405 * Fires when the layout for this region is changed.
51406 * @param {Roo.LayoutRegion} this
51408 "invalidated" : true,
51410 * @event visibilitychange
51411 * Fires when this region is shown or hidden
51412 * @param {Roo.LayoutRegion} this
51413 * @param {Boolean} visibility true or false
51415 "visibilitychange" : true,
51417 * @event paneladded
51418 * Fires when a panel is added.
51419 * @param {Roo.LayoutRegion} this
51420 * @param {Roo.ContentPanel} panel The panel
51422 "paneladded" : true,
51424 * @event panelremoved
51425 * Fires when a panel is removed.
51426 * @param {Roo.LayoutRegion} this
51427 * @param {Roo.ContentPanel} panel The panel
51429 "panelremoved" : true,
51432 * Fires when this region is collapsed.
51433 * @param {Roo.LayoutRegion} this
51435 "collapsed" : true,
51438 * Fires when this region is expanded.
51439 * @param {Roo.LayoutRegion} this
51444 * Fires when this region is slid into view.
51445 * @param {Roo.LayoutRegion} this
51447 "slideshow" : true,
51450 * Fires when this region slides out of view.
51451 * @param {Roo.LayoutRegion} this
51453 "slidehide" : true,
51455 * @event panelactivated
51456 * Fires when a panel is activated.
51457 * @param {Roo.LayoutRegion} this
51458 * @param {Roo.ContentPanel} panel The activated panel
51460 "panelactivated" : true,
51463 * Fires when the user resizes this region.
51464 * @param {Roo.LayoutRegion} this
51465 * @param {Number} newSize The new size (width for east/west, height for north/south)
51469 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51470 this.panels = new Roo.util.MixedCollection();
51471 this.panels.getKey = this.getPanelId.createDelegate(this);
51473 this.activePanel = null;
51474 // ensure listeners are added...
51476 if (config.listeners || config.events) {
51477 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51478 listeners : config.listeners || {},
51479 events : config.events || {}
51483 if(skipConfig !== true){
51484 this.applyConfig(config);
51488 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51489 getPanelId : function(p){
51493 applyConfig : function(config){
51494 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51495 this.config = config;
51500 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51501 * the width, for horizontal (north, south) the height.
51502 * @param {Number} newSize The new width or height
51504 resizeTo : function(newSize){
51505 var el = this.el ? this.el :
51506 (this.activePanel ? this.activePanel.getEl() : null);
51508 switch(this.position){
51511 el.setWidth(newSize);
51512 this.fireEvent("resized", this, newSize);
51516 el.setHeight(newSize);
51517 this.fireEvent("resized", this, newSize);
51523 getBox : function(){
51524 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51527 getMargins : function(){
51528 return this.margins;
51531 updateBox : function(box){
51533 var el = this.activePanel.getEl();
51534 el.dom.style.left = box.x + "px";
51535 el.dom.style.top = box.y + "px";
51536 this.activePanel.setSize(box.width, box.height);
51540 * Returns the container element for this region.
51541 * @return {Roo.Element}
51543 getEl : function(){
51544 return this.activePanel;
51548 * Returns true if this region is currently visible.
51549 * @return {Boolean}
51551 isVisible : function(){
51552 return this.activePanel ? true : false;
51555 setActivePanel : function(panel){
51556 panel = this.getPanel(panel);
51557 if(this.activePanel && this.activePanel != panel){
51558 this.activePanel.setActiveState(false);
51559 this.activePanel.getEl().setLeftTop(-10000,-10000);
51561 this.activePanel = panel;
51562 panel.setActiveState(true);
51564 panel.setSize(this.box.width, this.box.height);
51566 this.fireEvent("panelactivated", this, panel);
51567 this.fireEvent("invalidated");
51571 * Show the specified panel.
51572 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51573 * @return {Roo.ContentPanel} The shown panel or null
51575 showPanel : function(panel){
51576 if(panel = this.getPanel(panel)){
51577 this.setActivePanel(panel);
51583 * Get the active panel for this region.
51584 * @return {Roo.ContentPanel} The active panel or null
51586 getActivePanel : function(){
51587 return this.activePanel;
51591 * Add the passed ContentPanel(s)
51592 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51593 * @return {Roo.ContentPanel} The panel added (if only one was added)
51595 add : function(panel){
51596 if(arguments.length > 1){
51597 for(var i = 0, len = arguments.length; i < len; i++) {
51598 this.add(arguments[i]);
51602 if(this.hasPanel(panel)){
51603 this.showPanel(panel);
51606 var el = panel.getEl();
51607 if(el.dom.parentNode != this.mgr.el.dom){
51608 this.mgr.el.dom.appendChild(el.dom);
51610 if(panel.setRegion){
51611 panel.setRegion(this);
51613 this.panels.add(panel);
51614 el.setStyle("position", "absolute");
51615 if(!panel.background){
51616 this.setActivePanel(panel);
51617 if(this.config.initialSize && this.panels.getCount()==1){
51618 this.resizeTo(this.config.initialSize);
51621 this.fireEvent("paneladded", this, panel);
51626 * Returns true if the panel is in this region.
51627 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51628 * @return {Boolean}
51630 hasPanel : function(panel){
51631 if(typeof panel == "object"){ // must be panel obj
51632 panel = panel.getId();
51634 return this.getPanel(panel) ? true : false;
51638 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51639 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51640 * @param {Boolean} preservePanel Overrides the config preservePanel option
51641 * @return {Roo.ContentPanel} The panel that was removed
51643 remove : function(panel, preservePanel){
51644 panel = this.getPanel(panel);
51649 this.fireEvent("beforeremove", this, panel, e);
51650 if(e.cancel === true){
51653 var panelId = panel.getId();
51654 this.panels.removeKey(panelId);
51659 * Returns the panel specified or null if it's not in this region.
51660 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51661 * @return {Roo.ContentPanel}
51663 getPanel : function(id){
51664 if(typeof id == "object"){ // must be panel obj
51667 return this.panels.get(id);
51671 * Returns this regions position (north/south/east/west/center).
51674 getPosition: function(){
51675 return this.position;
51679 * Ext JS Library 1.1.1
51680 * Copyright(c) 2006-2007, Ext JS, LLC.
51682 * Originally Released Under LGPL - original licence link has changed is not relivant.
51685 * <script type="text/javascript">
51689 * @class Roo.LayoutRegion
51690 * @extends Roo.BasicLayoutRegion
51691 * This class represents a region in a layout manager.
51692 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51693 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51694 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51695 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51696 * @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})
51697 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51698 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51699 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51700 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51701 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51702 * @cfg {String} title The title for the region (overrides panel titles)
51703 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51704 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51705 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51706 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51707 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51708 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51709 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51710 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51711 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51712 * @cfg {Boolean} showPin True to show a pin button
51713 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51714 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51715 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51716 * @cfg {Number} width For East/West panels
51717 * @cfg {Number} height For North/South panels
51718 * @cfg {Boolean} split To show the splitter
51719 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51721 Roo.LayoutRegion = function(mgr, config, pos){
51722 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51723 var dh = Roo.DomHelper;
51724 /** This region's container element
51725 * @type Roo.Element */
51726 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51727 /** This region's title element
51728 * @type Roo.Element */
51730 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51731 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51732 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51734 this.titleEl.enableDisplayMode();
51735 /** This region's title text element
51736 * @type HTMLElement */
51737 this.titleTextEl = this.titleEl.dom.firstChild;
51738 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51739 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51740 this.closeBtn.enableDisplayMode();
51741 this.closeBtn.on("click", this.closeClicked, this);
51742 this.closeBtn.hide();
51744 this.createBody(config);
51745 this.visible = true;
51746 this.collapsed = false;
51748 if(config.hideWhenEmpty){
51750 this.on("paneladded", this.validateVisibility, this);
51751 this.on("panelremoved", this.validateVisibility, this);
51753 this.applyConfig(config);
51756 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51758 createBody : function(){
51759 /** This region's body element
51760 * @type Roo.Element */
51761 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51764 applyConfig : function(c){
51765 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51766 var dh = Roo.DomHelper;
51767 if(c.titlebar !== false){
51768 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51769 this.collapseBtn.on("click", this.collapse, this);
51770 this.collapseBtn.enableDisplayMode();
51772 if(c.showPin === true || this.showPin){
51773 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51774 this.stickBtn.enableDisplayMode();
51775 this.stickBtn.on("click", this.expand, this);
51776 this.stickBtn.hide();
51779 /** This region's collapsed element
51780 * @type Roo.Element */
51781 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51782 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51784 if(c.floatable !== false){
51785 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51786 this.collapsedEl.on("click", this.collapseClick, this);
51789 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51790 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51791 id: "message", unselectable: "on", style:{"float":"left"}});
51792 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51794 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51795 this.expandBtn.on("click", this.expand, this);
51797 if(this.collapseBtn){
51798 this.collapseBtn.setVisible(c.collapsible == true);
51800 this.cmargins = c.cmargins || this.cmargins ||
51801 (this.position == "west" || this.position == "east" ?
51802 {top: 0, left: 2, right:2, bottom: 0} :
51803 {top: 2, left: 0, right:0, bottom: 2});
51804 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51805 this.bottomTabs = c.tabPosition != "top";
51806 this.autoScroll = c.autoScroll || false;
51807 if(this.autoScroll){
51808 this.bodyEl.setStyle("overflow", "auto");
51810 this.bodyEl.setStyle("overflow", "hidden");
51812 //if(c.titlebar !== false){
51813 if((!c.titlebar && !c.title) || c.titlebar === false){
51814 this.titleEl.hide();
51816 this.titleEl.show();
51818 this.titleTextEl.innerHTML = c.title;
51822 this.duration = c.duration || .30;
51823 this.slideDuration = c.slideDuration || .45;
51826 this.collapse(true);
51833 * Returns true if this region is currently visible.
51834 * @return {Boolean}
51836 isVisible : function(){
51837 return this.visible;
51841 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51842 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
51844 setCollapsedTitle : function(title){
51845 title = title || " ";
51846 if(this.collapsedTitleTextEl){
51847 this.collapsedTitleTextEl.innerHTML = title;
51851 getBox : function(){
51853 if(!this.collapsed){
51854 b = this.el.getBox(false, true);
51856 b = this.collapsedEl.getBox(false, true);
51861 getMargins : function(){
51862 return this.collapsed ? this.cmargins : this.margins;
51865 highlight : function(){
51866 this.el.addClass("x-layout-panel-dragover");
51869 unhighlight : function(){
51870 this.el.removeClass("x-layout-panel-dragover");
51873 updateBox : function(box){
51875 if(!this.collapsed){
51876 this.el.dom.style.left = box.x + "px";
51877 this.el.dom.style.top = box.y + "px";
51878 this.updateBody(box.width, box.height);
51880 this.collapsedEl.dom.style.left = box.x + "px";
51881 this.collapsedEl.dom.style.top = box.y + "px";
51882 this.collapsedEl.setSize(box.width, box.height);
51885 this.tabs.autoSizeTabs();
51889 updateBody : function(w, h){
51891 this.el.setWidth(w);
51892 w -= this.el.getBorderWidth("rl");
51893 if(this.config.adjustments){
51894 w += this.config.adjustments[0];
51898 this.el.setHeight(h);
51899 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
51900 h -= this.el.getBorderWidth("tb");
51901 if(this.config.adjustments){
51902 h += this.config.adjustments[1];
51904 this.bodyEl.setHeight(h);
51906 h = this.tabs.syncHeight(h);
51909 if(this.panelSize){
51910 w = w !== null ? w : this.panelSize.width;
51911 h = h !== null ? h : this.panelSize.height;
51913 if(this.activePanel){
51914 var el = this.activePanel.getEl();
51915 w = w !== null ? w : el.getWidth();
51916 h = h !== null ? h : el.getHeight();
51917 this.panelSize = {width: w, height: h};
51918 this.activePanel.setSize(w, h);
51920 if(Roo.isIE && this.tabs){
51921 this.tabs.el.repaint();
51926 * Returns the container element for this region.
51927 * @return {Roo.Element}
51929 getEl : function(){
51934 * Hides this region.
51937 if(!this.collapsed){
51938 this.el.dom.style.left = "-2000px";
51941 this.collapsedEl.dom.style.left = "-2000px";
51942 this.collapsedEl.hide();
51944 this.visible = false;
51945 this.fireEvent("visibilitychange", this, false);
51949 * Shows this region if it was previously hidden.
51952 if(!this.collapsed){
51955 this.collapsedEl.show();
51957 this.visible = true;
51958 this.fireEvent("visibilitychange", this, true);
51961 closeClicked : function(){
51962 if(this.activePanel){
51963 this.remove(this.activePanel);
51967 collapseClick : function(e){
51969 e.stopPropagation();
51972 e.stopPropagation();
51978 * Collapses this region.
51979 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
51981 collapse : function(skipAnim){
51982 if(this.collapsed) {
51985 this.collapsed = true;
51987 this.split.el.hide();
51989 if(this.config.animate && skipAnim !== true){
51990 this.fireEvent("invalidated", this);
51991 this.animateCollapse();
51993 this.el.setLocation(-20000,-20000);
51995 this.collapsedEl.show();
51996 this.fireEvent("collapsed", this);
51997 this.fireEvent("invalidated", this);
52001 animateCollapse : function(){
52006 * Expands this region if it was previously collapsed.
52007 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52008 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52010 expand : function(e, skipAnim){
52012 e.stopPropagation();
52014 if(!this.collapsed || this.el.hasActiveFx()) {
52018 this.afterSlideIn();
52021 this.collapsed = false;
52022 if(this.config.animate && skipAnim !== true){
52023 this.animateExpand();
52027 this.split.el.show();
52029 this.collapsedEl.setLocation(-2000,-2000);
52030 this.collapsedEl.hide();
52031 this.fireEvent("invalidated", this);
52032 this.fireEvent("expanded", this);
52036 animateExpand : function(){
52040 initTabs : function()
52042 this.bodyEl.setStyle("overflow", "hidden");
52043 var ts = new Roo.TabPanel(
52046 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52047 disableTooltips: this.config.disableTabTips,
52048 toolbar : this.config.toolbar
52051 if(this.config.hideTabs){
52052 ts.stripWrap.setDisplayed(false);
52055 ts.resizeTabs = this.config.resizeTabs === true;
52056 ts.minTabWidth = this.config.minTabWidth || 40;
52057 ts.maxTabWidth = this.config.maxTabWidth || 250;
52058 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52059 ts.monitorResize = false;
52060 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52061 ts.bodyEl.addClass('x-layout-tabs-body');
52062 this.panels.each(this.initPanelAsTab, this);
52065 initPanelAsTab : function(panel){
52066 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52067 this.config.closeOnTab && panel.isClosable());
52068 if(panel.tabTip !== undefined){
52069 ti.setTooltip(panel.tabTip);
52071 ti.on("activate", function(){
52072 this.setActivePanel(panel);
52074 if(this.config.closeOnTab){
52075 ti.on("beforeclose", function(t, e){
52077 this.remove(panel);
52083 updatePanelTitle : function(panel, title){
52084 if(this.activePanel == panel){
52085 this.updateTitle(title);
52088 var ti = this.tabs.getTab(panel.getEl().id);
52090 if(panel.tabTip !== undefined){
52091 ti.setTooltip(panel.tabTip);
52096 updateTitle : function(title){
52097 if(this.titleTextEl && !this.config.title){
52098 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52102 setActivePanel : function(panel){
52103 panel = this.getPanel(panel);
52104 if(this.activePanel && this.activePanel != panel){
52105 this.activePanel.setActiveState(false);
52107 this.activePanel = panel;
52108 panel.setActiveState(true);
52109 if(this.panelSize){
52110 panel.setSize(this.panelSize.width, this.panelSize.height);
52113 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52115 this.updateTitle(panel.getTitle());
52117 this.fireEvent("invalidated", this);
52119 this.fireEvent("panelactivated", this, panel);
52123 * Shows the specified panel.
52124 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52125 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52127 showPanel : function(panel)
52129 panel = this.getPanel(panel);
52132 var tab = this.tabs.getTab(panel.getEl().id);
52133 if(tab.isHidden()){
52134 this.tabs.unhideTab(tab.id);
52138 this.setActivePanel(panel);
52145 * Get the active panel for this region.
52146 * @return {Roo.ContentPanel} The active panel or null
52148 getActivePanel : function(){
52149 return this.activePanel;
52152 validateVisibility : function(){
52153 if(this.panels.getCount() < 1){
52154 this.updateTitle(" ");
52155 this.closeBtn.hide();
52158 if(!this.isVisible()){
52165 * Adds the passed ContentPanel(s) to this region.
52166 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52167 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52169 add : function(panel){
52170 if(arguments.length > 1){
52171 for(var i = 0, len = arguments.length; i < len; i++) {
52172 this.add(arguments[i]);
52176 if(this.hasPanel(panel)){
52177 this.showPanel(panel);
52180 panel.setRegion(this);
52181 this.panels.add(panel);
52182 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52183 this.bodyEl.dom.appendChild(panel.getEl().dom);
52184 if(panel.background !== true){
52185 this.setActivePanel(panel);
52187 this.fireEvent("paneladded", this, panel);
52193 this.initPanelAsTab(panel);
52195 if(panel.background !== true){
52196 this.tabs.activate(panel.getEl().id);
52198 this.fireEvent("paneladded", this, panel);
52203 * Hides the tab for the specified panel.
52204 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52206 hidePanel : function(panel){
52207 if(this.tabs && (panel = this.getPanel(panel))){
52208 this.tabs.hideTab(panel.getEl().id);
52213 * Unhides the tab for a previously hidden panel.
52214 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52216 unhidePanel : function(panel){
52217 if(this.tabs && (panel = this.getPanel(panel))){
52218 this.tabs.unhideTab(panel.getEl().id);
52222 clearPanels : function(){
52223 while(this.panels.getCount() > 0){
52224 this.remove(this.panels.first());
52229 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52230 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52231 * @param {Boolean} preservePanel Overrides the config preservePanel option
52232 * @return {Roo.ContentPanel} The panel that was removed
52234 remove : function(panel, preservePanel){
52235 panel = this.getPanel(panel);
52240 this.fireEvent("beforeremove", this, panel, e);
52241 if(e.cancel === true){
52244 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52245 var panelId = panel.getId();
52246 this.panels.removeKey(panelId);
52248 document.body.appendChild(panel.getEl().dom);
52251 this.tabs.removeTab(panel.getEl().id);
52252 }else if (!preservePanel){
52253 this.bodyEl.dom.removeChild(panel.getEl().dom);
52255 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52256 var p = this.panels.first();
52257 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52258 tempEl.appendChild(p.getEl().dom);
52259 this.bodyEl.update("");
52260 this.bodyEl.dom.appendChild(p.getEl().dom);
52262 this.updateTitle(p.getTitle());
52264 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52265 this.setActivePanel(p);
52267 panel.setRegion(null);
52268 if(this.activePanel == panel){
52269 this.activePanel = null;
52271 if(this.config.autoDestroy !== false && preservePanel !== true){
52272 try{panel.destroy();}catch(e){}
52274 this.fireEvent("panelremoved", this, panel);
52279 * Returns the TabPanel component used by this region
52280 * @return {Roo.TabPanel}
52282 getTabs : function(){
52286 createTool : function(parentEl, className){
52287 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52288 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52289 btn.addClassOnOver("x-layout-tools-button-over");
52294 * Ext JS Library 1.1.1
52295 * Copyright(c) 2006-2007, Ext JS, LLC.
52297 * Originally Released Under LGPL - original licence link has changed is not relivant.
52300 * <script type="text/javascript">
52306 * @class Roo.SplitLayoutRegion
52307 * @extends Roo.LayoutRegion
52308 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52310 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52311 this.cursor = cursor;
52312 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52315 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52316 splitTip : "Drag to resize.",
52317 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52318 useSplitTips : false,
52320 applyConfig : function(config){
52321 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52324 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52325 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52326 /** The SplitBar for this region
52327 * @type Roo.SplitBar */
52328 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52329 this.split.on("moved", this.onSplitMove, this);
52330 this.split.useShim = config.useShim === true;
52331 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52332 if(this.useSplitTips){
52333 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52335 if(config.collapsible){
52336 this.split.el.on("dblclick", this.collapse, this);
52339 if(typeof config.minSize != "undefined"){
52340 this.split.minSize = config.minSize;
52342 if(typeof config.maxSize != "undefined"){
52343 this.split.maxSize = config.maxSize;
52345 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52346 this.hideSplitter();
52351 getHMaxSize : function(){
52352 var cmax = this.config.maxSize || 10000;
52353 var center = this.mgr.getRegion("center");
52354 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52357 getVMaxSize : function(){
52358 var cmax = this.config.maxSize || 10000;
52359 var center = this.mgr.getRegion("center");
52360 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52363 onSplitMove : function(split, newSize){
52364 this.fireEvent("resized", this, newSize);
52368 * Returns the {@link Roo.SplitBar} for this region.
52369 * @return {Roo.SplitBar}
52371 getSplitBar : function(){
52376 this.hideSplitter();
52377 Roo.SplitLayoutRegion.superclass.hide.call(this);
52380 hideSplitter : function(){
52382 this.split.el.setLocation(-2000,-2000);
52383 this.split.el.hide();
52389 this.split.el.show();
52391 Roo.SplitLayoutRegion.superclass.show.call(this);
52394 beforeSlide: function(){
52395 if(Roo.isGecko){// firefox overflow auto bug workaround
52396 this.bodyEl.clip();
52398 this.tabs.bodyEl.clip();
52400 if(this.activePanel){
52401 this.activePanel.getEl().clip();
52403 if(this.activePanel.beforeSlide){
52404 this.activePanel.beforeSlide();
52410 afterSlide : function(){
52411 if(Roo.isGecko){// firefox overflow auto bug workaround
52412 this.bodyEl.unclip();
52414 this.tabs.bodyEl.unclip();
52416 if(this.activePanel){
52417 this.activePanel.getEl().unclip();
52418 if(this.activePanel.afterSlide){
52419 this.activePanel.afterSlide();
52425 initAutoHide : function(){
52426 if(this.autoHide !== false){
52427 if(!this.autoHideHd){
52428 var st = new Roo.util.DelayedTask(this.slideIn, this);
52429 this.autoHideHd = {
52430 "mouseout": function(e){
52431 if(!e.within(this.el, true)){
52435 "mouseover" : function(e){
52441 this.el.on(this.autoHideHd);
52445 clearAutoHide : function(){
52446 if(this.autoHide !== false){
52447 this.el.un("mouseout", this.autoHideHd.mouseout);
52448 this.el.un("mouseover", this.autoHideHd.mouseover);
52452 clearMonitor : function(){
52453 Roo.get(document).un("click", this.slideInIf, this);
52456 // these names are backwards but not changed for compat
52457 slideOut : function(){
52458 if(this.isSlid || this.el.hasActiveFx()){
52461 this.isSlid = true;
52462 if(this.collapseBtn){
52463 this.collapseBtn.hide();
52465 this.closeBtnState = this.closeBtn.getStyle('display');
52466 this.closeBtn.hide();
52468 this.stickBtn.show();
52471 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52472 this.beforeSlide();
52473 this.el.setStyle("z-index", 10001);
52474 this.el.slideIn(this.getSlideAnchor(), {
52475 callback: function(){
52477 this.initAutoHide();
52478 Roo.get(document).on("click", this.slideInIf, this);
52479 this.fireEvent("slideshow", this);
52486 afterSlideIn : function(){
52487 this.clearAutoHide();
52488 this.isSlid = false;
52489 this.clearMonitor();
52490 this.el.setStyle("z-index", "");
52491 if(this.collapseBtn){
52492 this.collapseBtn.show();
52494 this.closeBtn.setStyle('display', this.closeBtnState);
52496 this.stickBtn.hide();
52498 this.fireEvent("slidehide", this);
52501 slideIn : function(cb){
52502 if(!this.isSlid || this.el.hasActiveFx()){
52506 this.isSlid = false;
52507 this.beforeSlide();
52508 this.el.slideOut(this.getSlideAnchor(), {
52509 callback: function(){
52510 this.el.setLeftTop(-10000, -10000);
52512 this.afterSlideIn();
52520 slideInIf : function(e){
52521 if(!e.within(this.el)){
52526 animateCollapse : function(){
52527 this.beforeSlide();
52528 this.el.setStyle("z-index", 20000);
52529 var anchor = this.getSlideAnchor();
52530 this.el.slideOut(anchor, {
52531 callback : function(){
52532 this.el.setStyle("z-index", "");
52533 this.collapsedEl.slideIn(anchor, {duration:.3});
52535 this.el.setLocation(-10000,-10000);
52537 this.fireEvent("collapsed", this);
52544 animateExpand : function(){
52545 this.beforeSlide();
52546 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52547 this.el.setStyle("z-index", 20000);
52548 this.collapsedEl.hide({
52551 this.el.slideIn(this.getSlideAnchor(), {
52552 callback : function(){
52553 this.el.setStyle("z-index", "");
52556 this.split.el.show();
52558 this.fireEvent("invalidated", this);
52559 this.fireEvent("expanded", this);
52587 getAnchor : function(){
52588 return this.anchors[this.position];
52591 getCollapseAnchor : function(){
52592 return this.canchors[this.position];
52595 getSlideAnchor : function(){
52596 return this.sanchors[this.position];
52599 getAlignAdj : function(){
52600 var cm = this.cmargins;
52601 switch(this.position){
52617 getExpandAdj : function(){
52618 var c = this.collapsedEl, cm = this.cmargins;
52619 switch(this.position){
52621 return [-(cm.right+c.getWidth()+cm.left), 0];
52624 return [cm.right+c.getWidth()+cm.left, 0];
52627 return [0, -(cm.top+cm.bottom+c.getHeight())];
52630 return [0, cm.top+cm.bottom+c.getHeight()];
52636 * Ext JS Library 1.1.1
52637 * Copyright(c) 2006-2007, Ext JS, LLC.
52639 * Originally Released Under LGPL - original licence link has changed is not relivant.
52642 * <script type="text/javascript">
52645 * These classes are private internal classes
52647 Roo.CenterLayoutRegion = function(mgr, config){
52648 Roo.LayoutRegion.call(this, mgr, config, "center");
52649 this.visible = true;
52650 this.minWidth = config.minWidth || 20;
52651 this.minHeight = config.minHeight || 20;
52654 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52656 // center panel can't be hidden
52660 // center panel can't be hidden
52663 getMinWidth: function(){
52664 return this.minWidth;
52667 getMinHeight: function(){
52668 return this.minHeight;
52673 Roo.NorthLayoutRegion = function(mgr, config){
52674 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52676 this.split.placement = Roo.SplitBar.TOP;
52677 this.split.orientation = Roo.SplitBar.VERTICAL;
52678 this.split.el.addClass("x-layout-split-v");
52680 var size = config.initialSize || config.height;
52681 if(typeof size != "undefined"){
52682 this.el.setHeight(size);
52685 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52686 orientation: Roo.SplitBar.VERTICAL,
52687 getBox : function(){
52688 if(this.collapsed){
52689 return this.collapsedEl.getBox();
52691 var box = this.el.getBox();
52693 box.height += this.split.el.getHeight();
52698 updateBox : function(box){
52699 if(this.split && !this.collapsed){
52700 box.height -= this.split.el.getHeight();
52701 this.split.el.setLeft(box.x);
52702 this.split.el.setTop(box.y+box.height);
52703 this.split.el.setWidth(box.width);
52705 if(this.collapsed){
52706 this.updateBody(box.width, null);
52708 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52712 Roo.SouthLayoutRegion = function(mgr, config){
52713 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52715 this.split.placement = Roo.SplitBar.BOTTOM;
52716 this.split.orientation = Roo.SplitBar.VERTICAL;
52717 this.split.el.addClass("x-layout-split-v");
52719 var size = config.initialSize || config.height;
52720 if(typeof size != "undefined"){
52721 this.el.setHeight(size);
52724 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52725 orientation: Roo.SplitBar.VERTICAL,
52726 getBox : function(){
52727 if(this.collapsed){
52728 return this.collapsedEl.getBox();
52730 var box = this.el.getBox();
52732 var sh = this.split.el.getHeight();
52739 updateBox : function(box){
52740 if(this.split && !this.collapsed){
52741 var sh = this.split.el.getHeight();
52744 this.split.el.setLeft(box.x);
52745 this.split.el.setTop(box.y-sh);
52746 this.split.el.setWidth(box.width);
52748 if(this.collapsed){
52749 this.updateBody(box.width, null);
52751 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52755 Roo.EastLayoutRegion = function(mgr, config){
52756 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52758 this.split.placement = Roo.SplitBar.RIGHT;
52759 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52760 this.split.el.addClass("x-layout-split-h");
52762 var size = config.initialSize || config.width;
52763 if(typeof size != "undefined"){
52764 this.el.setWidth(size);
52767 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52768 orientation: Roo.SplitBar.HORIZONTAL,
52769 getBox : function(){
52770 if(this.collapsed){
52771 return this.collapsedEl.getBox();
52773 var box = this.el.getBox();
52775 var sw = this.split.el.getWidth();
52782 updateBox : function(box){
52783 if(this.split && !this.collapsed){
52784 var sw = this.split.el.getWidth();
52786 this.split.el.setLeft(box.x);
52787 this.split.el.setTop(box.y);
52788 this.split.el.setHeight(box.height);
52791 if(this.collapsed){
52792 this.updateBody(null, box.height);
52794 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52798 Roo.WestLayoutRegion = function(mgr, config){
52799 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52801 this.split.placement = Roo.SplitBar.LEFT;
52802 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52803 this.split.el.addClass("x-layout-split-h");
52805 var size = config.initialSize || config.width;
52806 if(typeof size != "undefined"){
52807 this.el.setWidth(size);
52810 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52811 orientation: Roo.SplitBar.HORIZONTAL,
52812 getBox : function(){
52813 if(this.collapsed){
52814 return this.collapsedEl.getBox();
52816 var box = this.el.getBox();
52818 box.width += this.split.el.getWidth();
52823 updateBox : function(box){
52824 if(this.split && !this.collapsed){
52825 var sw = this.split.el.getWidth();
52827 this.split.el.setLeft(box.x+box.width);
52828 this.split.el.setTop(box.y);
52829 this.split.el.setHeight(box.height);
52831 if(this.collapsed){
52832 this.updateBody(null, box.height);
52834 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52839 * Ext JS Library 1.1.1
52840 * Copyright(c) 2006-2007, Ext JS, LLC.
52842 * Originally Released Under LGPL - original licence link has changed is not relivant.
52845 * <script type="text/javascript">
52850 * Private internal class for reading and applying state
52852 Roo.LayoutStateManager = function(layout){
52853 // default empty state
52862 Roo.LayoutStateManager.prototype = {
52863 init : function(layout, provider){
52864 this.provider = provider;
52865 var state = provider.get(layout.id+"-layout-state");
52867 var wasUpdating = layout.isUpdating();
52869 layout.beginUpdate();
52871 for(var key in state){
52872 if(typeof state[key] != "function"){
52873 var rstate = state[key];
52874 var r = layout.getRegion(key);
52877 r.resizeTo(rstate.size);
52879 if(rstate.collapsed == true){
52882 r.expand(null, true);
52888 layout.endUpdate();
52890 this.state = state;
52892 this.layout = layout;
52893 layout.on("regionresized", this.onRegionResized, this);
52894 layout.on("regioncollapsed", this.onRegionCollapsed, this);
52895 layout.on("regionexpanded", this.onRegionExpanded, this);
52898 storeState : function(){
52899 this.provider.set(this.layout.id+"-layout-state", this.state);
52902 onRegionResized : function(region, newSize){
52903 this.state[region.getPosition()].size = newSize;
52907 onRegionCollapsed : function(region){
52908 this.state[region.getPosition()].collapsed = true;
52912 onRegionExpanded : function(region){
52913 this.state[region.getPosition()].collapsed = false;
52918 * Ext JS Library 1.1.1
52919 * Copyright(c) 2006-2007, Ext JS, LLC.
52921 * Originally Released Under LGPL - original licence link has changed is not relivant.
52924 * <script type="text/javascript">
52927 * @class Roo.ContentPanel
52928 * @extends Roo.util.Observable
52929 * A basic ContentPanel element.
52930 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
52931 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
52932 * @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
52933 * @cfg {Boolean} closable True if the panel can be closed/removed
52934 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
52935 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
52936 * @cfg {Toolbar} toolbar A toolbar for this panel
52937 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
52938 * @cfg {String} title The title for this panel
52939 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
52940 * @cfg {String} url Calls {@link #setUrl} with this value
52941 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
52942 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
52943 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
52944 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
52947 * Create a new ContentPanel.
52948 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
52949 * @param {String/Object} config A string to set only the title or a config object
52950 * @param {String} content (optional) Set the HTML content for this panel
52951 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
52953 Roo.ContentPanel = function(el, config, content){
52957 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
52961 if (config && config.parentLayout) {
52962 el = config.parentLayout.el.createChild();
52965 if(el.autoCreate){ // xtype is available if this is called from factory
52969 this.el = Roo.get(el);
52970 if(!this.el && config && config.autoCreate){
52971 if(typeof config.autoCreate == "object"){
52972 if(!config.autoCreate.id){
52973 config.autoCreate.id = config.id||el;
52975 this.el = Roo.DomHelper.append(document.body,
52976 config.autoCreate, true);
52978 this.el = Roo.DomHelper.append(document.body,
52979 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
52982 this.closable = false;
52983 this.loaded = false;
52984 this.active = false;
52985 if(typeof config == "string"){
52986 this.title = config;
52988 Roo.apply(this, config);
52991 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
52992 this.wrapEl = this.el.wrap();
52993 this.toolbar.container = this.el.insertSibling(false, 'before');
52994 this.toolbar = new Roo.Toolbar(this.toolbar);
52997 // xtype created footer. - not sure if will work as we normally have to render first..
52998 if (this.footer && !this.footer.el && this.footer.xtype) {
52999 if (!this.wrapEl) {
53000 this.wrapEl = this.el.wrap();
53003 this.footer.container = this.wrapEl.createChild();
53005 this.footer = Roo.factory(this.footer, Roo);
53010 this.resizeEl = Roo.get(this.resizeEl, true);
53012 this.resizeEl = this.el;
53014 // handle view.xtype
53022 * Fires when this panel is activated.
53023 * @param {Roo.ContentPanel} this
53027 * @event deactivate
53028 * Fires when this panel is activated.
53029 * @param {Roo.ContentPanel} this
53031 "deactivate" : true,
53035 * Fires when this panel is resized if fitToFrame is true.
53036 * @param {Roo.ContentPanel} this
53037 * @param {Number} width The width after any component adjustments
53038 * @param {Number} height The height after any component adjustments
53044 * Fires when this tab is created
53045 * @param {Roo.ContentPanel} this
53056 if(this.autoScroll){
53057 this.resizeEl.setStyle("overflow", "auto");
53059 // fix randome scrolling
53060 this.el.on('scroll', function() {
53061 Roo.log('fix random scolling');
53062 this.scrollTo('top',0);
53065 content = content || this.content;
53067 this.setContent(content);
53069 if(config && config.url){
53070 this.setUrl(this.url, this.params, this.loadOnce);
53075 Roo.ContentPanel.superclass.constructor.call(this);
53077 if (this.view && typeof(this.view.xtype) != 'undefined') {
53078 this.view.el = this.el.appendChild(document.createElement("div"));
53079 this.view = Roo.factory(this.view);
53080 this.view.render && this.view.render(false, '');
53084 this.fireEvent('render', this);
53087 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53089 setRegion : function(region){
53090 this.region = region;
53092 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53094 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53099 * Returns the toolbar for this Panel if one was configured.
53100 * @return {Roo.Toolbar}
53102 getToolbar : function(){
53103 return this.toolbar;
53106 setActiveState : function(active){
53107 this.active = active;
53109 this.fireEvent("deactivate", this);
53111 this.fireEvent("activate", this);
53115 * Updates this panel's element
53116 * @param {String} content The new content
53117 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53119 setContent : function(content, loadScripts){
53120 this.el.update(content, loadScripts);
53123 ignoreResize : function(w, h){
53124 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53127 this.lastSize = {width: w, height: h};
53132 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53133 * @return {Roo.UpdateManager} The UpdateManager
53135 getUpdateManager : function(){
53136 return this.el.getUpdateManager();
53139 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53140 * @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:
53143 url: "your-url.php",
53144 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53145 callback: yourFunction,
53146 scope: yourObject, //(optional scope)
53149 text: "Loading...",
53154 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53155 * 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.
53156 * @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}
53157 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53158 * @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.
53159 * @return {Roo.ContentPanel} this
53162 var um = this.el.getUpdateManager();
53163 um.update.apply(um, arguments);
53169 * 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.
53170 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53171 * @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)
53172 * @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)
53173 * @return {Roo.UpdateManager} The UpdateManager
53175 setUrl : function(url, params, loadOnce){
53176 if(this.refreshDelegate){
53177 this.removeListener("activate", this.refreshDelegate);
53179 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53180 this.on("activate", this.refreshDelegate);
53181 return this.el.getUpdateManager();
53184 _handleRefresh : function(url, params, loadOnce){
53185 if(!loadOnce || !this.loaded){
53186 var updater = this.el.getUpdateManager();
53187 updater.update(url, params, this._setLoaded.createDelegate(this));
53191 _setLoaded : function(){
53192 this.loaded = true;
53196 * Returns this panel's id
53199 getId : function(){
53204 * Returns this panel's element - used by regiosn to add.
53205 * @return {Roo.Element}
53207 getEl : function(){
53208 return this.wrapEl || this.el;
53211 adjustForComponents : function(width, height)
53213 //Roo.log('adjustForComponents ');
53214 if(this.resizeEl != this.el){
53215 width -= this.el.getFrameWidth('lr');
53216 height -= this.el.getFrameWidth('tb');
53219 var te = this.toolbar.getEl();
53220 height -= te.getHeight();
53221 te.setWidth(width);
53224 var te = this.footer.getEl();
53225 Roo.log("footer:" + te.getHeight());
53227 height -= te.getHeight();
53228 te.setWidth(width);
53232 if(this.adjustments){
53233 width += this.adjustments[0];
53234 height += this.adjustments[1];
53236 return {"width": width, "height": height};
53239 setSize : function(width, height){
53240 if(this.fitToFrame && !this.ignoreResize(width, height)){
53241 if(this.fitContainer && this.resizeEl != this.el){
53242 this.el.setSize(width, height);
53244 var size = this.adjustForComponents(width, height);
53245 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53246 this.fireEvent('resize', this, size.width, size.height);
53251 * Returns this panel's title
53254 getTitle : function(){
53259 * Set this panel's title
53260 * @param {String} title
53262 setTitle : function(title){
53263 this.title = title;
53265 this.region.updatePanelTitle(this, title);
53270 * Returns true is this panel was configured to be closable
53271 * @return {Boolean}
53273 isClosable : function(){
53274 return this.closable;
53277 beforeSlide : function(){
53279 this.resizeEl.clip();
53282 afterSlide : function(){
53284 this.resizeEl.unclip();
53288 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53289 * Will fail silently if the {@link #setUrl} method has not been called.
53290 * This does not activate the panel, just updates its content.
53292 refresh : function(){
53293 if(this.refreshDelegate){
53294 this.loaded = false;
53295 this.refreshDelegate();
53300 * Destroys this panel
53302 destroy : function(){
53303 this.el.removeAllListeners();
53304 var tempEl = document.createElement("span");
53305 tempEl.appendChild(this.el.dom);
53306 tempEl.innerHTML = "";
53312 * form - if the content panel contains a form - this is a reference to it.
53313 * @type {Roo.form.Form}
53317 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53318 * This contains a reference to it.
53324 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53334 * @param {Object} cfg Xtype definition of item to add.
53337 addxtype : function(cfg) {
53339 if (cfg.xtype.match(/^Form$/)) {
53342 //if (this.footer) {
53343 // el = this.footer.container.insertSibling(false, 'before');
53345 el = this.el.createChild();
53348 this.form = new Roo.form.Form(cfg);
53351 if ( this.form.allItems.length) {
53352 this.form.render(el.dom);
53356 // should only have one of theses..
53357 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53358 // views.. should not be just added - used named prop 'view''
53360 cfg.el = this.el.appendChild(document.createElement("div"));
53363 var ret = new Roo.factory(cfg);
53365 ret.render && ret.render(false, ''); // render blank..
53374 * @class Roo.GridPanel
53375 * @extends Roo.ContentPanel
53377 * Create a new GridPanel.
53378 * @param {Roo.grid.Grid} grid The grid for this panel
53379 * @param {String/Object} config A string to set only the panel's title, or a config object
53381 Roo.GridPanel = function(grid, config){
53384 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53385 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53387 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53389 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53392 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53394 // xtype created footer. - not sure if will work as we normally have to render first..
53395 if (this.footer && !this.footer.el && this.footer.xtype) {
53397 this.footer.container = this.grid.getView().getFooterPanel(true);
53398 this.footer.dataSource = this.grid.dataSource;
53399 this.footer = Roo.factory(this.footer, Roo);
53403 grid.monitorWindowResize = false; // turn off autosizing
53404 grid.autoHeight = false;
53405 grid.autoWidth = false;
53407 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53410 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53411 getId : function(){
53412 return this.grid.id;
53416 * Returns the grid for this panel
53417 * @return {Roo.grid.Grid}
53419 getGrid : function(){
53423 setSize : function(width, height){
53424 if(!this.ignoreResize(width, height)){
53425 var grid = this.grid;
53426 var size = this.adjustForComponents(width, height);
53427 grid.getGridEl().setSize(size.width, size.height);
53432 beforeSlide : function(){
53433 this.grid.getView().scroller.clip();
53436 afterSlide : function(){
53437 this.grid.getView().scroller.unclip();
53440 destroy : function(){
53441 this.grid.destroy();
53443 Roo.GridPanel.superclass.destroy.call(this);
53449 * @class Roo.NestedLayoutPanel
53450 * @extends Roo.ContentPanel
53452 * Create a new NestedLayoutPanel.
53455 * @param {Roo.BorderLayout} layout The layout for this panel
53456 * @param {String/Object} config A string to set only the title or a config object
53458 Roo.NestedLayoutPanel = function(layout, config)
53460 // construct with only one argument..
53461 /* FIXME - implement nicer consturctors
53462 if (layout.layout) {
53464 layout = config.layout;
53465 delete config.layout;
53467 if (layout.xtype && !layout.getEl) {
53468 // then layout needs constructing..
53469 layout = Roo.factory(layout, Roo);
53474 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53476 layout.monitorWindowResize = false; // turn off autosizing
53477 this.layout = layout;
53478 this.layout.getEl().addClass("x-layout-nested-layout");
53485 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53487 setSize : function(width, height){
53488 if(!this.ignoreResize(width, height)){
53489 var size = this.adjustForComponents(width, height);
53490 var el = this.layout.getEl();
53491 el.setSize(size.width, size.height);
53492 var touch = el.dom.offsetWidth;
53493 this.layout.layout();
53494 // ie requires a double layout on the first pass
53495 if(Roo.isIE && !this.initialized){
53496 this.initialized = true;
53497 this.layout.layout();
53502 // activate all subpanels if not currently active..
53504 setActiveState : function(active){
53505 this.active = active;
53507 this.fireEvent("deactivate", this);
53511 this.fireEvent("activate", this);
53512 // not sure if this should happen before or after..
53513 if (!this.layout) {
53514 return; // should not happen..
53517 for (var r in this.layout.regions) {
53518 reg = this.layout.getRegion(r);
53519 if (reg.getActivePanel()) {
53520 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53521 reg.setActivePanel(reg.getActivePanel());
53524 if (!reg.panels.length) {
53527 reg.showPanel(reg.getPanel(0));
53536 * Returns the nested BorderLayout for this panel
53537 * @return {Roo.BorderLayout}
53539 getLayout : function(){
53540 return this.layout;
53544 * Adds a xtype elements to the layout of the nested panel
53548 xtype : 'ContentPanel',
53555 xtype : 'NestedLayoutPanel',
53561 items : [ ... list of content panels or nested layout panels.. ]
53565 * @param {Object} cfg Xtype definition of item to add.
53567 addxtype : function(cfg) {
53568 return this.layout.addxtype(cfg);
53573 Roo.ScrollPanel = function(el, config, content){
53574 config = config || {};
53575 config.fitToFrame = true;
53576 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53578 this.el.dom.style.overflow = "hidden";
53579 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53580 this.el.removeClass("x-layout-inactive-content");
53581 this.el.on("mousewheel", this.onWheel, this);
53583 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53584 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53585 up.unselectable(); down.unselectable();
53586 up.on("click", this.scrollUp, this);
53587 down.on("click", this.scrollDown, this);
53588 up.addClassOnOver("x-scroller-btn-over");
53589 down.addClassOnOver("x-scroller-btn-over");
53590 up.addClassOnClick("x-scroller-btn-click");
53591 down.addClassOnClick("x-scroller-btn-click");
53592 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53594 this.resizeEl = this.el;
53595 this.el = wrap; this.up = up; this.down = down;
53598 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53600 wheelIncrement : 5,
53601 scrollUp : function(){
53602 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53605 scrollDown : function(){
53606 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53609 afterScroll : function(){
53610 var el = this.resizeEl;
53611 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53612 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53613 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53616 setSize : function(){
53617 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53618 this.afterScroll();
53621 onWheel : function(e){
53622 var d = e.getWheelDelta();
53623 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53624 this.afterScroll();
53628 setContent : function(content, loadScripts){
53629 this.resizeEl.update(content, loadScripts);
53643 * @class Roo.TreePanel
53644 * @extends Roo.ContentPanel
53646 * Create a new TreePanel. - defaults to fit/scoll contents.
53647 * @param {String/Object} config A string to set only the panel's title, or a config object
53648 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53650 Roo.TreePanel = function(config){
53651 var el = config.el;
53652 var tree = config.tree;
53653 delete config.tree;
53654 delete config.el; // hopefull!
53656 // wrapper for IE7 strict & safari scroll issue
53658 var treeEl = el.createChild();
53659 config.resizeEl = treeEl;
53663 Roo.TreePanel.superclass.constructor.call(this, el, config);
53666 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53667 //console.log(tree);
53668 this.on('activate', function()
53670 if (this.tree.rendered) {
53673 //console.log('render tree');
53674 this.tree.render();
53676 // this should not be needed.. - it's actually the 'el' that resizes?
53677 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53679 //this.on('resize', function (cp, w, h) {
53680 // this.tree.innerCt.setWidth(w);
53681 // this.tree.innerCt.setHeight(h);
53682 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53689 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53706 * Ext JS Library 1.1.1
53707 * Copyright(c) 2006-2007, Ext JS, LLC.
53709 * Originally Released Under LGPL - original licence link has changed is not relivant.
53712 * <script type="text/javascript">
53717 * @class Roo.ReaderLayout
53718 * @extends Roo.BorderLayout
53719 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53720 * center region containing two nested regions (a top one for a list view and one for item preview below),
53721 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53722 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53723 * expedites the setup of the overall layout and regions for this common application style.
53726 var reader = new Roo.ReaderLayout();
53727 var CP = Roo.ContentPanel; // shortcut for adding
53729 reader.beginUpdate();
53730 reader.add("north", new CP("north", "North"));
53731 reader.add("west", new CP("west", {title: "West"}));
53732 reader.add("east", new CP("east", {title: "East"}));
53734 reader.regions.listView.add(new CP("listView", "List"));
53735 reader.regions.preview.add(new CP("preview", "Preview"));
53736 reader.endUpdate();
53739 * Create a new ReaderLayout
53740 * @param {Object} config Configuration options
53741 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53742 * document.body if omitted)
53744 Roo.ReaderLayout = function(config, renderTo){
53745 var c = config || {size:{}};
53746 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53747 north: c.north !== false ? Roo.apply({
53751 }, c.north) : false,
53752 west: c.west !== false ? Roo.apply({
53760 margins:{left:5,right:0,bottom:5,top:5},
53761 cmargins:{left:5,right:5,bottom:5,top:5}
53762 }, c.west) : false,
53763 east: c.east !== false ? Roo.apply({
53771 margins:{left:0,right:5,bottom:5,top:5},
53772 cmargins:{left:5,right:5,bottom:5,top:5}
53773 }, c.east) : false,
53774 center: Roo.apply({
53775 tabPosition: 'top',
53779 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53783 this.el.addClass('x-reader');
53785 this.beginUpdate();
53787 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53788 south: c.preview !== false ? Roo.apply({
53795 cmargins:{top:5,left:0, right:0, bottom:0}
53796 }, c.preview) : false,
53797 center: Roo.apply({
53803 this.add('center', new Roo.NestedLayoutPanel(inner,
53804 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53808 this.regions.preview = inner.getRegion('south');
53809 this.regions.listView = inner.getRegion('center');
53812 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53814 * Ext JS Library 1.1.1
53815 * Copyright(c) 2006-2007, Ext JS, LLC.
53817 * Originally Released Under LGPL - original licence link has changed is not relivant.
53820 * <script type="text/javascript">
53824 * @class Roo.grid.Grid
53825 * @extends Roo.util.Observable
53826 * This class represents the primary interface of a component based grid control.
53827 * <br><br>Usage:<pre><code>
53828 var grid = new Roo.grid.Grid("my-container-id", {
53831 selModel: mySelectionModel,
53832 autoSizeColumns: true,
53833 monitorWindowResize: false,
53834 trackMouseOver: true
53839 * <b>Common Problems:</b><br/>
53840 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
53841 * element will correct this<br/>
53842 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
53843 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
53844 * are unpredictable.<br/>
53845 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
53846 * grid to calculate dimensions/offsets.<br/>
53848 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53849 * The container MUST have some type of size defined for the grid to fill. The container will be
53850 * automatically set to position relative if it isn't already.
53851 * @param {Object} config A config object that sets properties on this grid.
53853 Roo.grid.Grid = function(container, config){
53854 // initialize the container
53855 this.container = Roo.get(container);
53856 this.container.update("");
53857 this.container.setStyle("overflow", "hidden");
53858 this.container.addClass('x-grid-container');
53860 this.id = this.container.id;
53862 Roo.apply(this, config);
53863 // check and correct shorthanded configs
53865 this.dataSource = this.ds;
53869 this.colModel = this.cm;
53873 this.selModel = this.sm;
53877 if (this.selModel) {
53878 this.selModel = Roo.factory(this.selModel, Roo.grid);
53879 this.sm = this.selModel;
53880 this.sm.xmodule = this.xmodule || false;
53882 if (typeof(this.colModel.config) == 'undefined') {
53883 this.colModel = new Roo.grid.ColumnModel(this.colModel);
53884 this.cm = this.colModel;
53885 this.cm.xmodule = this.xmodule || false;
53887 if (this.dataSource) {
53888 this.dataSource= Roo.factory(this.dataSource, Roo.data);
53889 this.ds = this.dataSource;
53890 this.ds.xmodule = this.xmodule || false;
53897 this.container.setWidth(this.width);
53901 this.container.setHeight(this.height);
53908 * The raw click event for the entire grid.
53909 * @param {Roo.EventObject} e
53914 * The raw dblclick event for the entire grid.
53915 * @param {Roo.EventObject} e
53919 * @event contextmenu
53920 * The raw contextmenu event for the entire grid.
53921 * @param {Roo.EventObject} e
53923 "contextmenu" : true,
53926 * The raw mousedown event for the entire grid.
53927 * @param {Roo.EventObject} e
53929 "mousedown" : true,
53932 * The raw mouseup event for the entire grid.
53933 * @param {Roo.EventObject} e
53938 * The raw mouseover event for the entire grid.
53939 * @param {Roo.EventObject} e
53941 "mouseover" : true,
53944 * The raw mouseout event for the entire grid.
53945 * @param {Roo.EventObject} e
53950 * The raw keypress event for the entire grid.
53951 * @param {Roo.EventObject} e
53956 * The raw keydown event for the entire grid.
53957 * @param {Roo.EventObject} e
53965 * Fires when a cell is clicked
53966 * @param {Grid} this
53967 * @param {Number} rowIndex
53968 * @param {Number} columnIndex
53969 * @param {Roo.EventObject} e
53971 "cellclick" : true,
53973 * @event celldblclick
53974 * Fires when a cell is double clicked
53975 * @param {Grid} this
53976 * @param {Number} rowIndex
53977 * @param {Number} columnIndex
53978 * @param {Roo.EventObject} e
53980 "celldblclick" : true,
53983 * Fires when a row is clicked
53984 * @param {Grid} this
53985 * @param {Number} rowIndex
53986 * @param {Roo.EventObject} e
53990 * @event rowdblclick
53991 * Fires when a row is double clicked
53992 * @param {Grid} this
53993 * @param {Number} rowIndex
53994 * @param {Roo.EventObject} e
53996 "rowdblclick" : true,
53998 * @event headerclick
53999 * Fires when a header is clicked
54000 * @param {Grid} this
54001 * @param {Number} columnIndex
54002 * @param {Roo.EventObject} e
54004 "headerclick" : true,
54006 * @event headerdblclick
54007 * Fires when a header cell is double clicked
54008 * @param {Grid} this
54009 * @param {Number} columnIndex
54010 * @param {Roo.EventObject} e
54012 "headerdblclick" : true,
54014 * @event rowcontextmenu
54015 * Fires when a row is right clicked
54016 * @param {Grid} this
54017 * @param {Number} rowIndex
54018 * @param {Roo.EventObject} e
54020 "rowcontextmenu" : true,
54022 * @event cellcontextmenu
54023 * Fires when a cell is right clicked
54024 * @param {Grid} this
54025 * @param {Number} rowIndex
54026 * @param {Number} cellIndex
54027 * @param {Roo.EventObject} e
54029 "cellcontextmenu" : true,
54031 * @event headercontextmenu
54032 * Fires when a header is right clicked
54033 * @param {Grid} this
54034 * @param {Number} columnIndex
54035 * @param {Roo.EventObject} e
54037 "headercontextmenu" : true,
54039 * @event bodyscroll
54040 * Fires when the body element is scrolled
54041 * @param {Number} scrollLeft
54042 * @param {Number} scrollTop
54044 "bodyscroll" : true,
54046 * @event columnresize
54047 * Fires when the user resizes a column
54048 * @param {Number} columnIndex
54049 * @param {Number} newSize
54051 "columnresize" : true,
54053 * @event columnmove
54054 * Fires when the user moves a column
54055 * @param {Number} oldIndex
54056 * @param {Number} newIndex
54058 "columnmove" : true,
54061 * Fires when row(s) start being dragged
54062 * @param {Grid} this
54063 * @param {Roo.GridDD} dd The drag drop object
54064 * @param {event} e The raw browser event
54066 "startdrag" : true,
54069 * Fires when a drag operation is complete
54070 * @param {Grid} this
54071 * @param {Roo.GridDD} dd The drag drop object
54072 * @param {event} e The raw browser event
54077 * Fires when dragged row(s) are dropped on a valid DD target
54078 * @param {Grid} this
54079 * @param {Roo.GridDD} dd The drag drop object
54080 * @param {String} targetId The target drag drop object
54081 * @param {event} e The raw browser event
54086 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54087 * @param {Grid} this
54088 * @param {Roo.GridDD} dd The drag drop object
54089 * @param {String} targetId The target drag drop object
54090 * @param {event} e The raw browser event
54095 * Fires when the dragged row(s) first cross another DD target while being dragged
54096 * @param {Grid} this
54097 * @param {Roo.GridDD} dd The drag drop object
54098 * @param {String} targetId The target drag drop object
54099 * @param {event} e The raw browser event
54101 "dragenter" : true,
54104 * Fires when the dragged row(s) leave another DD target while being dragged
54105 * @param {Grid} this
54106 * @param {Roo.GridDD} dd The drag drop object
54107 * @param {String} targetId The target drag drop object
54108 * @param {event} e The raw browser event
54113 * Fires when a row is rendered, so you can change add a style to it.
54114 * @param {GridView} gridview The grid view
54115 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54121 * Fires when the grid is rendered
54122 * @param {Grid} grid
54127 Roo.grid.Grid.superclass.constructor.call(this);
54129 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54132 * @cfg {String} ddGroup - drag drop group.
54136 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54138 minColumnWidth : 25,
54141 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54142 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54143 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54145 autoSizeColumns : false,
54148 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54150 autoSizeHeaders : true,
54153 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54155 monitorWindowResize : true,
54158 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54159 * rows measured to get a columns size. Default is 0 (all rows).
54161 maxRowsToMeasure : 0,
54164 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54166 trackMouseOver : true,
54169 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54173 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54175 enableDragDrop : false,
54178 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54180 enableColumnMove : true,
54183 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54185 enableColumnHide : true,
54188 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54190 enableRowHeightSync : false,
54193 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54198 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54200 autoHeight : false,
54203 * @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.
54205 autoExpandColumn : false,
54208 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54211 autoExpandMin : 50,
54214 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54216 autoExpandMax : 1000,
54219 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54224 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54228 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54238 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54239 * of a fixed width. Default is false.
54242 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54245 * Called once after all setup has been completed and the grid is ready to be rendered.
54246 * @return {Roo.grid.Grid} this
54248 render : function()
54250 var c = this.container;
54251 // try to detect autoHeight/width mode
54252 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54253 this.autoHeight = true;
54255 var view = this.getView();
54258 c.on("click", this.onClick, this);
54259 c.on("dblclick", this.onDblClick, this);
54260 c.on("contextmenu", this.onContextMenu, this);
54261 c.on("keydown", this.onKeyDown, this);
54263 c.on("touchstart", this.onTouchStart, this);
54266 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54268 this.getSelectionModel().init(this);
54273 this.loadMask = new Roo.LoadMask(this.container,
54274 Roo.apply({store:this.dataSource}, this.loadMask));
54278 if (this.toolbar && this.toolbar.xtype) {
54279 this.toolbar.container = this.getView().getHeaderPanel(true);
54280 this.toolbar = new Roo.Toolbar(this.toolbar);
54282 if (this.footer && this.footer.xtype) {
54283 this.footer.dataSource = this.getDataSource();
54284 this.footer.container = this.getView().getFooterPanel(true);
54285 this.footer = Roo.factory(this.footer, Roo);
54287 if (this.dropTarget && this.dropTarget.xtype) {
54288 delete this.dropTarget.xtype;
54289 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54293 this.rendered = true;
54294 this.fireEvent('render', this);
54299 * Reconfigures the grid to use a different Store and Column Model.
54300 * The View will be bound to the new objects and refreshed.
54301 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54302 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54304 reconfigure : function(dataSource, colModel){
54306 this.loadMask.destroy();
54307 this.loadMask = new Roo.LoadMask(this.container,
54308 Roo.apply({store:dataSource}, this.loadMask));
54310 this.view.bind(dataSource, colModel);
54311 this.dataSource = dataSource;
54312 this.colModel = colModel;
54313 this.view.refresh(true);
54317 onKeyDown : function(e){
54318 this.fireEvent("keydown", e);
54322 * Destroy this grid.
54323 * @param {Boolean} removeEl True to remove the element
54325 destroy : function(removeEl, keepListeners){
54327 this.loadMask.destroy();
54329 var c = this.container;
54330 c.removeAllListeners();
54331 this.view.destroy();
54332 this.colModel.purgeListeners();
54333 if(!keepListeners){
54334 this.purgeListeners();
54337 if(removeEl === true){
54343 processEvent : function(name, e){
54344 // does this fire select???
54345 //Roo.log('grid:processEvent ' + name);
54347 if (name != 'touchstart' ) {
54348 this.fireEvent(name, e);
54351 var t = e.getTarget();
54353 var header = v.findHeaderIndex(t);
54354 if(header !== false){
54355 var ename = name == 'touchstart' ? 'click' : name;
54357 this.fireEvent("header" + ename, this, header, e);
54359 var row = v.findRowIndex(t);
54360 var cell = v.findCellIndex(t);
54361 if (name == 'touchstart') {
54362 // first touch is always a click.
54363 // hopefull this happens after selection is updated.?
54366 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54367 var cs = this.selModel.getSelectedCell();
54368 if (row == cs[0] && cell == cs[1]){
54372 if (typeof(this.selModel.getSelections) != 'undefined') {
54373 var cs = this.selModel.getSelections();
54374 var ds = this.dataSource;
54375 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54386 this.fireEvent("row" + name, this, row, e);
54387 if(cell !== false){
54388 this.fireEvent("cell" + name, this, row, cell, e);
54395 onClick : function(e){
54396 this.processEvent("click", e);
54399 onTouchStart : function(e){
54400 this.processEvent("touchstart", e);
54404 onContextMenu : function(e, t){
54405 this.processEvent("contextmenu", e);
54409 onDblClick : function(e){
54410 this.processEvent("dblclick", e);
54414 walkCells : function(row, col, step, fn, scope){
54415 var cm = this.colModel, clen = cm.getColumnCount();
54416 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54428 if(fn.call(scope || this, row, col, cm) === true){
54446 if(fn.call(scope || this, row, col, cm) === true){
54458 getSelections : function(){
54459 return this.selModel.getSelections();
54463 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54464 * but if manual update is required this method will initiate it.
54466 autoSize : function(){
54468 this.view.layout();
54469 if(this.view.adjustForScroll){
54470 this.view.adjustForScroll();
54476 * Returns the grid's underlying element.
54477 * @return {Element} The element
54479 getGridEl : function(){
54480 return this.container;
54483 // private for compatibility, overridden by editor grid
54484 stopEditing : function(){},
54487 * Returns the grid's SelectionModel.
54488 * @return {SelectionModel}
54490 getSelectionModel : function(){
54491 if(!this.selModel){
54492 this.selModel = new Roo.grid.RowSelectionModel();
54494 return this.selModel;
54498 * Returns the grid's DataSource.
54499 * @return {DataSource}
54501 getDataSource : function(){
54502 return this.dataSource;
54506 * Returns the grid's ColumnModel.
54507 * @return {ColumnModel}
54509 getColumnModel : function(){
54510 return this.colModel;
54514 * Returns the grid's GridView object.
54515 * @return {GridView}
54517 getView : function(){
54519 this.view = new Roo.grid.GridView(this.viewConfig);
54524 * Called to get grid's drag proxy text, by default returns this.ddText.
54527 getDragDropText : function(){
54528 var count = this.selModel.getCount();
54529 return String.format(this.ddText, count, count == 1 ? '' : 's');
54533 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54534 * %0 is replaced with the number of selected rows.
54537 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54539 * Ext JS Library 1.1.1
54540 * Copyright(c) 2006-2007, Ext JS, LLC.
54542 * Originally Released Under LGPL - original licence link has changed is not relivant.
54545 * <script type="text/javascript">
54548 Roo.grid.AbstractGridView = function(){
54552 "beforerowremoved" : true,
54553 "beforerowsinserted" : true,
54554 "beforerefresh" : true,
54555 "rowremoved" : true,
54556 "rowsinserted" : true,
54557 "rowupdated" : true,
54560 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54563 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54564 rowClass : "x-grid-row",
54565 cellClass : "x-grid-cell",
54566 tdClass : "x-grid-td",
54567 hdClass : "x-grid-hd",
54568 splitClass : "x-grid-hd-split",
54570 init: function(grid){
54572 var cid = this.grid.getGridEl().id;
54573 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54574 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54575 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54576 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54579 getColumnRenderers : function(){
54580 var renderers = [];
54581 var cm = this.grid.colModel;
54582 var colCount = cm.getColumnCount();
54583 for(var i = 0; i < colCount; i++){
54584 renderers[i] = cm.getRenderer(i);
54589 getColumnIds : function(){
54591 var cm = this.grid.colModel;
54592 var colCount = cm.getColumnCount();
54593 for(var i = 0; i < colCount; i++){
54594 ids[i] = cm.getColumnId(i);
54599 getDataIndexes : function(){
54600 if(!this.indexMap){
54601 this.indexMap = this.buildIndexMap();
54603 return this.indexMap.colToData;
54606 getColumnIndexByDataIndex : function(dataIndex){
54607 if(!this.indexMap){
54608 this.indexMap = this.buildIndexMap();
54610 return this.indexMap.dataToCol[dataIndex];
54614 * Set a css style for a column dynamically.
54615 * @param {Number} colIndex The index of the column
54616 * @param {String} name The css property name
54617 * @param {String} value The css value
54619 setCSSStyle : function(colIndex, name, value){
54620 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54621 Roo.util.CSS.updateRule(selector, name, value);
54624 generateRules : function(cm){
54625 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54626 Roo.util.CSS.removeStyleSheet(rulesId);
54627 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54628 var cid = cm.getColumnId(i);
54629 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54630 this.tdSelector, cid, " {\n}\n",
54631 this.hdSelector, cid, " {\n}\n",
54632 this.splitSelector, cid, " {\n}\n");
54634 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54638 * Ext JS Library 1.1.1
54639 * Copyright(c) 2006-2007, Ext JS, LLC.
54641 * Originally Released Under LGPL - original licence link has changed is not relivant.
54644 * <script type="text/javascript">
54648 // This is a support class used internally by the Grid components
54649 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54651 this.view = grid.getView();
54652 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54653 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54655 this.setHandleElId(Roo.id(hd));
54656 this.setOuterHandleElId(Roo.id(hd2));
54658 this.scroll = false;
54660 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54662 getDragData : function(e){
54663 var t = Roo.lib.Event.getTarget(e);
54664 var h = this.view.findHeaderCell(t);
54666 return {ddel: h.firstChild, header:h};
54671 onInitDrag : function(e){
54672 this.view.headersDisabled = true;
54673 var clone = this.dragData.ddel.cloneNode(true);
54674 clone.id = Roo.id();
54675 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54676 this.proxy.update(clone);
54680 afterValidDrop : function(){
54682 setTimeout(function(){
54683 v.headersDisabled = false;
54687 afterInvalidDrop : function(){
54689 setTimeout(function(){
54690 v.headersDisabled = false;
54696 * Ext JS Library 1.1.1
54697 * Copyright(c) 2006-2007, Ext JS, LLC.
54699 * Originally Released Under LGPL - original licence link has changed is not relivant.
54702 * <script type="text/javascript">
54705 // This is a support class used internally by the Grid components
54706 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54708 this.view = grid.getView();
54709 // split the proxies so they don't interfere with mouse events
54710 this.proxyTop = Roo.DomHelper.append(document.body, {
54711 cls:"col-move-top", html:" "
54713 this.proxyBottom = Roo.DomHelper.append(document.body, {
54714 cls:"col-move-bottom", html:" "
54716 this.proxyTop.hide = this.proxyBottom.hide = function(){
54717 this.setLeftTop(-100,-100);
54718 this.setStyle("visibility", "hidden");
54720 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54721 // temporarily disabled
54722 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54723 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54725 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54726 proxyOffsets : [-4, -9],
54727 fly: Roo.Element.fly,
54729 getTargetFromEvent : function(e){
54730 var t = Roo.lib.Event.getTarget(e);
54731 var cindex = this.view.findCellIndex(t);
54732 if(cindex !== false){
54733 return this.view.getHeaderCell(cindex);
54738 nextVisible : function(h){
54739 var v = this.view, cm = this.grid.colModel;
54742 if(!cm.isHidden(v.getCellIndex(h))){
54750 prevVisible : function(h){
54751 var v = this.view, cm = this.grid.colModel;
54754 if(!cm.isHidden(v.getCellIndex(h))){
54762 positionIndicator : function(h, n, e){
54763 var x = Roo.lib.Event.getPageX(e);
54764 var r = Roo.lib.Dom.getRegion(n.firstChild);
54765 var px, pt, py = r.top + this.proxyOffsets[1];
54766 if((r.right - x) <= (r.right-r.left)/2){
54767 px = r.right+this.view.borderWidth;
54773 var oldIndex = this.view.getCellIndex(h);
54774 var newIndex = this.view.getCellIndex(n);
54776 if(this.grid.colModel.isFixed(newIndex)){
54780 var locked = this.grid.colModel.isLocked(newIndex);
54785 if(oldIndex < newIndex){
54788 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54791 px += this.proxyOffsets[0];
54792 this.proxyTop.setLeftTop(px, py);
54793 this.proxyTop.show();
54794 if(!this.bottomOffset){
54795 this.bottomOffset = this.view.mainHd.getHeight();
54797 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54798 this.proxyBottom.show();
54802 onNodeEnter : function(n, dd, e, data){
54803 if(data.header != n){
54804 this.positionIndicator(data.header, n, e);
54808 onNodeOver : function(n, dd, e, data){
54809 var result = false;
54810 if(data.header != n){
54811 result = this.positionIndicator(data.header, n, e);
54814 this.proxyTop.hide();
54815 this.proxyBottom.hide();
54817 return result ? this.dropAllowed : this.dropNotAllowed;
54820 onNodeOut : function(n, dd, e, data){
54821 this.proxyTop.hide();
54822 this.proxyBottom.hide();
54825 onNodeDrop : function(n, dd, e, data){
54826 var h = data.header;
54828 var cm = this.grid.colModel;
54829 var x = Roo.lib.Event.getPageX(e);
54830 var r = Roo.lib.Dom.getRegion(n.firstChild);
54831 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54832 var oldIndex = this.view.getCellIndex(h);
54833 var newIndex = this.view.getCellIndex(n);
54834 var locked = cm.isLocked(newIndex);
54838 if(oldIndex < newIndex){
54841 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
54844 cm.setLocked(oldIndex, locked, true);
54845 cm.moveColumn(oldIndex, newIndex);
54846 this.grid.fireEvent("columnmove", oldIndex, newIndex);
54854 * Ext JS Library 1.1.1
54855 * Copyright(c) 2006-2007, Ext JS, LLC.
54857 * Originally Released Under LGPL - original licence link has changed is not relivant.
54860 * <script type="text/javascript">
54864 * @class Roo.grid.GridView
54865 * @extends Roo.util.Observable
54868 * @param {Object} config
54870 Roo.grid.GridView = function(config){
54871 Roo.grid.GridView.superclass.constructor.call(this);
54874 Roo.apply(this, config);
54877 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
54879 unselectable : 'unselectable="on"',
54880 unselectableCls : 'x-unselectable',
54883 rowClass : "x-grid-row",
54885 cellClass : "x-grid-col",
54887 tdClass : "x-grid-td",
54889 hdClass : "x-grid-hd",
54891 splitClass : "x-grid-split",
54893 sortClasses : ["sort-asc", "sort-desc"],
54895 enableMoveAnim : false,
54899 dh : Roo.DomHelper,
54901 fly : Roo.Element.fly,
54903 css : Roo.util.CSS,
54909 scrollIncrement : 22,
54911 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
54913 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
54915 bind : function(ds, cm){
54917 this.ds.un("load", this.onLoad, this);
54918 this.ds.un("datachanged", this.onDataChange, this);
54919 this.ds.un("add", this.onAdd, this);
54920 this.ds.un("remove", this.onRemove, this);
54921 this.ds.un("update", this.onUpdate, this);
54922 this.ds.un("clear", this.onClear, this);
54925 ds.on("load", this.onLoad, this);
54926 ds.on("datachanged", this.onDataChange, this);
54927 ds.on("add", this.onAdd, this);
54928 ds.on("remove", this.onRemove, this);
54929 ds.on("update", this.onUpdate, this);
54930 ds.on("clear", this.onClear, this);
54935 this.cm.un("widthchange", this.onColWidthChange, this);
54936 this.cm.un("headerchange", this.onHeaderChange, this);
54937 this.cm.un("hiddenchange", this.onHiddenChange, this);
54938 this.cm.un("columnmoved", this.onColumnMove, this);
54939 this.cm.un("columnlockchange", this.onColumnLock, this);
54942 this.generateRules(cm);
54943 cm.on("widthchange", this.onColWidthChange, this);
54944 cm.on("headerchange", this.onHeaderChange, this);
54945 cm.on("hiddenchange", this.onHiddenChange, this);
54946 cm.on("columnmoved", this.onColumnMove, this);
54947 cm.on("columnlockchange", this.onColumnLock, this);
54952 init: function(grid){
54953 Roo.grid.GridView.superclass.init.call(this, grid);
54955 this.bind(grid.dataSource, grid.colModel);
54957 grid.on("headerclick", this.handleHeaderClick, this);
54959 if(grid.trackMouseOver){
54960 grid.on("mouseover", this.onRowOver, this);
54961 grid.on("mouseout", this.onRowOut, this);
54963 grid.cancelTextSelection = function(){};
54964 this.gridId = grid.id;
54966 var tpls = this.templates || {};
54969 tpls.master = new Roo.Template(
54970 '<div class="x-grid" hidefocus="true">',
54971 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
54972 '<div class="x-grid-topbar"></div>',
54973 '<div class="x-grid-scroller"><div></div></div>',
54974 '<div class="x-grid-locked">',
54975 '<div class="x-grid-header">{lockedHeader}</div>',
54976 '<div class="x-grid-body">{lockedBody}</div>',
54978 '<div class="x-grid-viewport">',
54979 '<div class="x-grid-header">{header}</div>',
54980 '<div class="x-grid-body">{body}</div>',
54982 '<div class="x-grid-bottombar"></div>',
54984 '<div class="x-grid-resize-proxy"> </div>',
54987 tpls.master.disableformats = true;
54991 tpls.header = new Roo.Template(
54992 '<table border="0" cellspacing="0" cellpadding="0">',
54993 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
54996 tpls.header.disableformats = true;
54998 tpls.header.compile();
55001 tpls.hcell = new Roo.Template(
55002 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55003 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55006 tpls.hcell.disableFormats = true;
55008 tpls.hcell.compile();
55011 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55012 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55013 tpls.hsplit.disableFormats = true;
55015 tpls.hsplit.compile();
55018 tpls.body = new Roo.Template(
55019 '<table border="0" cellspacing="0" cellpadding="0">',
55020 "<tbody>{rows}</tbody>",
55023 tpls.body.disableFormats = true;
55025 tpls.body.compile();
55028 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55029 tpls.row.disableFormats = true;
55031 tpls.row.compile();
55034 tpls.cell = new Roo.Template(
55035 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55036 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55037 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55040 tpls.cell.disableFormats = true;
55042 tpls.cell.compile();
55044 this.templates = tpls;
55047 // remap these for backwards compat
55048 onColWidthChange : function(){
55049 this.updateColumns.apply(this, arguments);
55051 onHeaderChange : function(){
55052 this.updateHeaders.apply(this, arguments);
55054 onHiddenChange : function(){
55055 this.handleHiddenChange.apply(this, arguments);
55057 onColumnMove : function(){
55058 this.handleColumnMove.apply(this, arguments);
55060 onColumnLock : function(){
55061 this.handleLockChange.apply(this, arguments);
55064 onDataChange : function(){
55066 this.updateHeaderSortState();
55069 onClear : function(){
55073 onUpdate : function(ds, record){
55074 this.refreshRow(record);
55077 refreshRow : function(record){
55078 var ds = this.ds, index;
55079 if(typeof record == 'number'){
55081 record = ds.getAt(index);
55083 index = ds.indexOf(record);
55085 this.insertRows(ds, index, index, true);
55086 this.onRemove(ds, record, index+1, true);
55087 this.syncRowHeights(index, index);
55089 this.fireEvent("rowupdated", this, index, record);
55092 onAdd : function(ds, records, index){
55093 this.insertRows(ds, index, index + (records.length-1));
55096 onRemove : function(ds, record, index, isUpdate){
55097 if(isUpdate !== true){
55098 this.fireEvent("beforerowremoved", this, index, record);
55100 var bt = this.getBodyTable(), lt = this.getLockedTable();
55101 if(bt.rows[index]){
55102 bt.firstChild.removeChild(bt.rows[index]);
55104 if(lt.rows[index]){
55105 lt.firstChild.removeChild(lt.rows[index]);
55107 if(isUpdate !== true){
55108 this.stripeRows(index);
55109 this.syncRowHeights(index, index);
55111 this.fireEvent("rowremoved", this, index, record);
55115 onLoad : function(){
55116 this.scrollToTop();
55120 * Scrolls the grid to the top
55122 scrollToTop : function(){
55124 this.scroller.dom.scrollTop = 0;
55130 * Gets a panel in the header of the grid that can be used for toolbars etc.
55131 * After modifying the contents of this panel a call to grid.autoSize() may be
55132 * required to register any changes in size.
55133 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55134 * @return Roo.Element
55136 getHeaderPanel : function(doShow){
55138 this.headerPanel.show();
55140 return this.headerPanel;
55144 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55145 * After modifying the contents of this panel a call to grid.autoSize() may be
55146 * required to register any changes in size.
55147 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55148 * @return Roo.Element
55150 getFooterPanel : function(doShow){
55152 this.footerPanel.show();
55154 return this.footerPanel;
55157 initElements : function(){
55158 var E = Roo.Element;
55159 var el = this.grid.getGridEl().dom.firstChild;
55160 var cs = el.childNodes;
55162 this.el = new E(el);
55164 this.focusEl = new E(el.firstChild);
55165 this.focusEl.swallowEvent("click", true);
55167 this.headerPanel = new E(cs[1]);
55168 this.headerPanel.enableDisplayMode("block");
55170 this.scroller = new E(cs[2]);
55171 this.scrollSizer = new E(this.scroller.dom.firstChild);
55173 this.lockedWrap = new E(cs[3]);
55174 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55175 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55177 this.mainWrap = new E(cs[4]);
55178 this.mainHd = new E(this.mainWrap.dom.firstChild);
55179 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55181 this.footerPanel = new E(cs[5]);
55182 this.footerPanel.enableDisplayMode("block");
55184 this.resizeProxy = new E(cs[6]);
55186 this.headerSelector = String.format(
55187 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55188 this.lockedHd.id, this.mainHd.id
55191 this.splitterSelector = String.format(
55192 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55193 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55196 idToCssName : function(s)
55198 return s.replace(/[^a-z0-9]+/ig, '-');
55201 getHeaderCell : function(index){
55202 return Roo.DomQuery.select(this.headerSelector)[index];
55205 getHeaderCellMeasure : function(index){
55206 return this.getHeaderCell(index).firstChild;
55209 getHeaderCellText : function(index){
55210 return this.getHeaderCell(index).firstChild.firstChild;
55213 getLockedTable : function(){
55214 return this.lockedBody.dom.firstChild;
55217 getBodyTable : function(){
55218 return this.mainBody.dom.firstChild;
55221 getLockedRow : function(index){
55222 return this.getLockedTable().rows[index];
55225 getRow : function(index){
55226 return this.getBodyTable().rows[index];
55229 getRowComposite : function(index){
55231 this.rowEl = new Roo.CompositeElementLite();
55233 var els = [], lrow, mrow;
55234 if(lrow = this.getLockedRow(index)){
55237 if(mrow = this.getRow(index)){
55240 this.rowEl.elements = els;
55244 * Gets the 'td' of the cell
55246 * @param {Integer} rowIndex row to select
55247 * @param {Integer} colIndex column to select
55251 getCell : function(rowIndex, colIndex){
55252 var locked = this.cm.getLockedCount();
55254 if(colIndex < locked){
55255 source = this.lockedBody.dom.firstChild;
55257 source = this.mainBody.dom.firstChild;
55258 colIndex -= locked;
55260 return source.rows[rowIndex].childNodes[colIndex];
55263 getCellText : function(rowIndex, colIndex){
55264 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55267 getCellBox : function(cell){
55268 var b = this.fly(cell).getBox();
55269 if(Roo.isOpera){ // opera fails to report the Y
55270 b.y = cell.offsetTop + this.mainBody.getY();
55275 getCellIndex : function(cell){
55276 var id = String(cell.className).match(this.cellRE);
55278 return parseInt(id[1], 10);
55283 findHeaderIndex : function(n){
55284 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55285 return r ? this.getCellIndex(r) : false;
55288 findHeaderCell : function(n){
55289 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55290 return r ? r : false;
55293 findRowIndex : function(n){
55297 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55298 return r ? r.rowIndex : false;
55301 findCellIndex : function(node){
55302 var stop = this.el.dom;
55303 while(node && node != stop){
55304 if(this.findRE.test(node.className)){
55305 return this.getCellIndex(node);
55307 node = node.parentNode;
55312 getColumnId : function(index){
55313 return this.cm.getColumnId(index);
55316 getSplitters : function()
55318 if(this.splitterSelector){
55319 return Roo.DomQuery.select(this.splitterSelector);
55325 getSplitter : function(index){
55326 return this.getSplitters()[index];
55329 onRowOver : function(e, t){
55331 if((row = this.findRowIndex(t)) !== false){
55332 this.getRowComposite(row).addClass("x-grid-row-over");
55336 onRowOut : function(e, t){
55338 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55339 this.getRowComposite(row).removeClass("x-grid-row-over");
55343 renderHeaders : function(){
55345 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55346 var cb = [], lb = [], sb = [], lsb = [], p = {};
55347 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55348 p.cellId = "x-grid-hd-0-" + i;
55349 p.splitId = "x-grid-csplit-0-" + i;
55350 p.id = cm.getColumnId(i);
55351 p.value = cm.getColumnHeader(i) || "";
55352 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55353 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55354 if(!cm.isLocked(i)){
55355 cb[cb.length] = ct.apply(p);
55356 sb[sb.length] = st.apply(p);
55358 lb[lb.length] = ct.apply(p);
55359 lsb[lsb.length] = st.apply(p);
55362 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55363 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55366 updateHeaders : function(){
55367 var html = this.renderHeaders();
55368 this.lockedHd.update(html[0]);
55369 this.mainHd.update(html[1]);
55373 * Focuses the specified row.
55374 * @param {Number} row The row index
55376 focusRow : function(row)
55378 //Roo.log('GridView.focusRow');
55379 var x = this.scroller.dom.scrollLeft;
55380 this.focusCell(row, 0, false);
55381 this.scroller.dom.scrollLeft = x;
55385 * Focuses the specified cell.
55386 * @param {Number} row The row index
55387 * @param {Number} col The column index
55388 * @param {Boolean} hscroll false to disable horizontal scrolling
55390 focusCell : function(row, col, hscroll)
55392 //Roo.log('GridView.focusCell');
55393 var el = this.ensureVisible(row, col, hscroll);
55394 this.focusEl.alignTo(el, "tl-tl");
55396 this.focusEl.focus();
55398 this.focusEl.focus.defer(1, this.focusEl);
55403 * Scrolls the specified cell into view
55404 * @param {Number} row The row index
55405 * @param {Number} col The column index
55406 * @param {Boolean} hscroll false to disable horizontal scrolling
55408 ensureVisible : function(row, col, hscroll)
55410 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55411 //return null; //disable for testing.
55412 if(typeof row != "number"){
55413 row = row.rowIndex;
55415 if(row < 0 && row >= this.ds.getCount()){
55418 col = (col !== undefined ? col : 0);
55419 var cm = this.grid.colModel;
55420 while(cm.isHidden(col)){
55424 var el = this.getCell(row, col);
55428 var c = this.scroller.dom;
55430 var ctop = parseInt(el.offsetTop, 10);
55431 var cleft = parseInt(el.offsetLeft, 10);
55432 var cbot = ctop + el.offsetHeight;
55433 var cright = cleft + el.offsetWidth;
55435 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55436 var stop = parseInt(c.scrollTop, 10);
55437 var sleft = parseInt(c.scrollLeft, 10);
55438 var sbot = stop + ch;
55439 var sright = sleft + c.clientWidth;
55441 Roo.log('GridView.ensureVisible:' +
55443 ' c.clientHeight:' + c.clientHeight +
55444 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55452 c.scrollTop = ctop;
55453 //Roo.log("set scrolltop to ctop DISABLE?");
55454 }else if(cbot > sbot){
55455 //Roo.log("set scrolltop to cbot-ch");
55456 c.scrollTop = cbot-ch;
55459 if(hscroll !== false){
55461 c.scrollLeft = cleft;
55462 }else if(cright > sright){
55463 c.scrollLeft = cright-c.clientWidth;
55470 updateColumns : function(){
55471 this.grid.stopEditing();
55472 var cm = this.grid.colModel, colIds = this.getColumnIds();
55473 //var totalWidth = cm.getTotalWidth();
55475 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55476 //if(cm.isHidden(i)) continue;
55477 var w = cm.getColumnWidth(i);
55478 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55479 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55481 this.updateSplitters();
55484 generateRules : function(cm){
55485 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55486 Roo.util.CSS.removeStyleSheet(rulesId);
55487 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55488 var cid = cm.getColumnId(i);
55490 if(cm.config[i].align){
55491 align = 'text-align:'+cm.config[i].align+';';
55494 if(cm.isHidden(i)){
55495 hidden = 'display:none;';
55497 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55499 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55500 this.hdSelector, cid, " {\n", align, width, "}\n",
55501 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55502 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55504 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55507 updateSplitters : function(){
55508 var cm = this.cm, s = this.getSplitters();
55509 if(s){ // splitters not created yet
55510 var pos = 0, locked = true;
55511 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55512 if(cm.isHidden(i)) {
55515 var w = cm.getColumnWidth(i); // make sure it's a number
55516 if(!cm.isLocked(i) && locked){
55521 s[i].style.left = (pos-this.splitOffset) + "px";
55526 handleHiddenChange : function(colModel, colIndex, hidden){
55528 this.hideColumn(colIndex);
55530 this.unhideColumn(colIndex);
55534 hideColumn : function(colIndex){
55535 var cid = this.getColumnId(colIndex);
55536 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55537 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55539 this.updateHeaders();
55541 this.updateSplitters();
55545 unhideColumn : function(colIndex){
55546 var cid = this.getColumnId(colIndex);
55547 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55548 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55551 this.updateHeaders();
55553 this.updateSplitters();
55557 insertRows : function(dm, firstRow, lastRow, isUpdate){
55558 if(firstRow == 0 && lastRow == dm.getCount()-1){
55562 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55564 var s = this.getScrollState();
55565 var markup = this.renderRows(firstRow, lastRow);
55566 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55567 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55568 this.restoreScroll(s);
55570 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55571 this.syncRowHeights(firstRow, lastRow);
55572 this.stripeRows(firstRow);
55578 bufferRows : function(markup, target, index){
55579 var before = null, trows = target.rows, tbody = target.tBodies[0];
55580 if(index < trows.length){
55581 before = trows[index];
55583 var b = document.createElement("div");
55584 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55585 var rows = b.firstChild.rows;
55586 for(var i = 0, len = rows.length; i < len; i++){
55588 tbody.insertBefore(rows[0], before);
55590 tbody.appendChild(rows[0]);
55597 deleteRows : function(dm, firstRow, lastRow){
55598 if(dm.getRowCount()<1){
55599 this.fireEvent("beforerefresh", this);
55600 this.mainBody.update("");
55601 this.lockedBody.update("");
55602 this.fireEvent("refresh", this);
55604 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55605 var bt = this.getBodyTable();
55606 var tbody = bt.firstChild;
55607 var rows = bt.rows;
55608 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55609 tbody.removeChild(rows[firstRow]);
55611 this.stripeRows(firstRow);
55612 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55616 updateRows : function(dataSource, firstRow, lastRow){
55617 var s = this.getScrollState();
55619 this.restoreScroll(s);
55622 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55626 this.updateHeaderSortState();
55629 getScrollState : function(){
55631 var sb = this.scroller.dom;
55632 return {left: sb.scrollLeft, top: sb.scrollTop};
55635 stripeRows : function(startRow){
55636 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55639 startRow = startRow || 0;
55640 var rows = this.getBodyTable().rows;
55641 var lrows = this.getLockedTable().rows;
55642 var cls = ' x-grid-row-alt ';
55643 for(var i = startRow, len = rows.length; i < len; i++){
55644 var row = rows[i], lrow = lrows[i];
55645 var isAlt = ((i+1) % 2 == 0);
55646 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55647 if(isAlt == hasAlt){
55651 row.className += " x-grid-row-alt";
55653 row.className = row.className.replace("x-grid-row-alt", "");
55656 lrow.className = row.className;
55661 restoreScroll : function(state){
55662 //Roo.log('GridView.restoreScroll');
55663 var sb = this.scroller.dom;
55664 sb.scrollLeft = state.left;
55665 sb.scrollTop = state.top;
55669 syncScroll : function(){
55670 //Roo.log('GridView.syncScroll');
55671 var sb = this.scroller.dom;
55672 var sh = this.mainHd.dom;
55673 var bs = this.mainBody.dom;
55674 var lv = this.lockedBody.dom;
55675 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55676 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55679 handleScroll : function(e){
55681 var sb = this.scroller.dom;
55682 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55686 handleWheel : function(e){
55687 var d = e.getWheelDelta();
55688 this.scroller.dom.scrollTop -= d*22;
55689 // set this here to prevent jumpy scrolling on large tables
55690 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55694 renderRows : function(startRow, endRow){
55695 // pull in all the crap needed to render rows
55696 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55697 var colCount = cm.getColumnCount();
55699 if(ds.getCount() < 1){
55703 // build a map for all the columns
55705 for(var i = 0; i < colCount; i++){
55706 var name = cm.getDataIndex(i);
55708 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55709 renderer : cm.getRenderer(i),
55710 id : cm.getColumnId(i),
55711 locked : cm.isLocked(i),
55712 has_editor : cm.isCellEditable(i)
55716 startRow = startRow || 0;
55717 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55719 // records to render
55720 var rs = ds.getRange(startRow, endRow);
55722 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55725 // As much as I hate to duplicate code, this was branched because FireFox really hates
55726 // [].join("") on strings. The performance difference was substantial enough to
55727 // branch this function
55728 doRender : Roo.isGecko ?
55729 function(cs, rs, ds, startRow, colCount, stripe){
55730 var ts = this.templates, ct = ts.cell, rt = ts.row;
55732 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55734 var hasListener = this.grid.hasListener('rowclass');
55736 for(var j = 0, len = rs.length; j < len; j++){
55737 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55738 for(var i = 0; i < colCount; i++){
55740 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55742 p.css = p.attr = "";
55743 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55744 if(p.value == undefined || p.value === "") {
55745 p.value = " ";
55748 p.css += ' x-grid-editable-cell';
55750 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55751 p.css += ' x-grid-dirty-cell';
55753 var markup = ct.apply(p);
55761 if(stripe && ((rowIndex+1) % 2 == 0)){
55762 alt.push("x-grid-row-alt")
55765 alt.push( " x-grid-dirty-row");
55768 if(this.getRowClass){
55769 alt.push(this.getRowClass(r, rowIndex));
55775 rowIndex : rowIndex,
55778 this.grid.fireEvent('rowclass', this, rowcfg);
55779 alt.push(rowcfg.rowClass);
55781 rp.alt = alt.join(" ");
55782 lbuf+= rt.apply(rp);
55784 buf+= rt.apply(rp);
55786 return [lbuf, buf];
55788 function(cs, rs, ds, startRow, colCount, stripe){
55789 var ts = this.templates, ct = ts.cell, rt = ts.row;
55791 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55792 var hasListener = this.grid.hasListener('rowclass');
55795 for(var j = 0, len = rs.length; j < len; j++){
55796 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55797 for(var i = 0; i < colCount; i++){
55799 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55801 p.css = p.attr = "";
55802 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55803 if(p.value == undefined || p.value === "") {
55804 p.value = " ";
55808 p.css += ' x-grid-editable-cell';
55810 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55811 p.css += ' x-grid-dirty-cell'
55814 var markup = ct.apply(p);
55816 cb[cb.length] = markup;
55818 lcb[lcb.length] = markup;
55822 if(stripe && ((rowIndex+1) % 2 == 0)){
55823 alt.push( "x-grid-row-alt");
55826 alt.push(" x-grid-dirty-row");
55829 if(this.getRowClass){
55830 alt.push( this.getRowClass(r, rowIndex));
55836 rowIndex : rowIndex,
55839 this.grid.fireEvent('rowclass', this, rowcfg);
55840 alt.push(rowcfg.rowClass);
55843 rp.alt = alt.join(" ");
55844 rp.cells = lcb.join("");
55845 lbuf[lbuf.length] = rt.apply(rp);
55846 rp.cells = cb.join("");
55847 buf[buf.length] = rt.apply(rp);
55849 return [lbuf.join(""), buf.join("")];
55852 renderBody : function(){
55853 var markup = this.renderRows();
55854 var bt = this.templates.body;
55855 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
55859 * Refreshes the grid
55860 * @param {Boolean} headersToo
55862 refresh : function(headersToo){
55863 this.fireEvent("beforerefresh", this);
55864 this.grid.stopEditing();
55865 var result = this.renderBody();
55866 this.lockedBody.update(result[0]);
55867 this.mainBody.update(result[1]);
55868 if(headersToo === true){
55869 this.updateHeaders();
55870 this.updateColumns();
55871 this.updateSplitters();
55872 this.updateHeaderSortState();
55874 this.syncRowHeights();
55876 this.fireEvent("refresh", this);
55879 handleColumnMove : function(cm, oldIndex, newIndex){
55880 this.indexMap = null;
55881 var s = this.getScrollState();
55882 this.refresh(true);
55883 this.restoreScroll(s);
55884 this.afterMove(newIndex);
55887 afterMove : function(colIndex){
55888 if(this.enableMoveAnim && Roo.enableFx){
55889 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
55891 // if multisort - fix sortOrder, and reload..
55892 if (this.grid.dataSource.multiSort) {
55893 // the we can call sort again..
55894 var dm = this.grid.dataSource;
55895 var cm = this.grid.colModel;
55897 for(var i = 0; i < cm.config.length; i++ ) {
55899 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
55900 continue; // dont' bother, it's not in sort list or being set.
55903 so.push(cm.config[i].dataIndex);
55906 dm.load(dm.lastOptions);
55913 updateCell : function(dm, rowIndex, dataIndex){
55914 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
55915 if(typeof colIndex == "undefined"){ // not present in grid
55918 var cm = this.grid.colModel;
55919 var cell = this.getCell(rowIndex, colIndex);
55920 var cellText = this.getCellText(rowIndex, colIndex);
55923 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
55924 id : cm.getColumnId(colIndex),
55925 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
55927 var renderer = cm.getRenderer(colIndex);
55928 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
55929 if(typeof val == "undefined" || val === "") {
55932 cellText.innerHTML = val;
55933 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
55934 this.syncRowHeights(rowIndex, rowIndex);
55937 calcColumnWidth : function(colIndex, maxRowsToMeasure){
55939 if(this.grid.autoSizeHeaders){
55940 var h = this.getHeaderCellMeasure(colIndex);
55941 maxWidth = Math.max(maxWidth, h.scrollWidth);
55944 if(this.cm.isLocked(colIndex)){
55945 tb = this.getLockedTable();
55948 tb = this.getBodyTable();
55949 index = colIndex - this.cm.getLockedCount();
55952 var rows = tb.rows;
55953 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
55954 for(var i = 0; i < stopIndex; i++){
55955 var cell = rows[i].childNodes[index].firstChild;
55956 maxWidth = Math.max(maxWidth, cell.scrollWidth);
55959 return maxWidth + /*margin for error in IE*/ 5;
55962 * Autofit a column to its content.
55963 * @param {Number} colIndex
55964 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
55966 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
55967 if(this.cm.isHidden(colIndex)){
55968 return; // can't calc a hidden column
55971 var cid = this.cm.getColumnId(colIndex);
55972 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
55973 if(this.grid.autoSizeHeaders){
55974 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
55977 var newWidth = this.calcColumnWidth(colIndex);
55978 this.cm.setColumnWidth(colIndex,
55979 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
55980 if(!suppressEvent){
55981 this.grid.fireEvent("columnresize", colIndex, newWidth);
55986 * Autofits all columns to their content and then expands to fit any extra space in the grid
55988 autoSizeColumns : function(){
55989 var cm = this.grid.colModel;
55990 var colCount = cm.getColumnCount();
55991 for(var i = 0; i < colCount; i++){
55992 this.autoSizeColumn(i, true, true);
55994 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
55997 this.updateColumns();
56003 * Autofits all columns to the grid's width proportionate with their current size
56004 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56006 fitColumns : function(reserveScrollSpace){
56007 var cm = this.grid.colModel;
56008 var colCount = cm.getColumnCount();
56012 for (i = 0; i < colCount; i++){
56013 if(!cm.isHidden(i) && !cm.isFixed(i)){
56014 w = cm.getColumnWidth(i);
56020 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56021 if(reserveScrollSpace){
56024 var frac = (avail - cm.getTotalWidth())/width;
56025 while (cols.length){
56028 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56030 this.updateColumns();
56034 onRowSelect : function(rowIndex){
56035 var row = this.getRowComposite(rowIndex);
56036 row.addClass("x-grid-row-selected");
56039 onRowDeselect : function(rowIndex){
56040 var row = this.getRowComposite(rowIndex);
56041 row.removeClass("x-grid-row-selected");
56044 onCellSelect : function(row, col){
56045 var cell = this.getCell(row, col);
56047 Roo.fly(cell).addClass("x-grid-cell-selected");
56051 onCellDeselect : function(row, col){
56052 var cell = this.getCell(row, col);
56054 Roo.fly(cell).removeClass("x-grid-cell-selected");
56058 updateHeaderSortState : function(){
56060 // sort state can be single { field: xxx, direction : yyy}
56061 // or { xxx=>ASC , yyy : DESC ..... }
56064 if (!this.ds.multiSort) {
56065 var state = this.ds.getSortState();
56069 mstate[state.field] = state.direction;
56070 // FIXME... - this is not used here.. but might be elsewhere..
56071 this.sortState = state;
56074 mstate = this.ds.sortToggle;
56076 //remove existing sort classes..
56078 var sc = this.sortClasses;
56079 var hds = this.el.select(this.headerSelector).removeClass(sc);
56081 for(var f in mstate) {
56083 var sortColumn = this.cm.findColumnIndex(f);
56085 if(sortColumn != -1){
56086 var sortDir = mstate[f];
56087 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56096 handleHeaderClick : function(g, index,e){
56098 Roo.log("header click");
56101 // touch events on header are handled by context
56102 this.handleHdCtx(g,index,e);
56107 if(this.headersDisabled){
56110 var dm = g.dataSource, cm = g.colModel;
56111 if(!cm.isSortable(index)){
56116 if (dm.multiSort) {
56117 // update the sortOrder
56119 for(var i = 0; i < cm.config.length; i++ ) {
56121 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56122 continue; // dont' bother, it's not in sort list or being set.
56125 so.push(cm.config[i].dataIndex);
56131 dm.sort(cm.getDataIndex(index));
56135 destroy : function(){
56137 this.colMenu.removeAll();
56138 Roo.menu.MenuMgr.unregister(this.colMenu);
56139 this.colMenu.getEl().remove();
56140 delete this.colMenu;
56143 this.hmenu.removeAll();
56144 Roo.menu.MenuMgr.unregister(this.hmenu);
56145 this.hmenu.getEl().remove();
56148 if(this.grid.enableColumnMove){
56149 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56151 for(var dd in dds){
56152 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56153 var elid = dds[dd].dragElId;
56155 Roo.get(elid).remove();
56156 } else if(dds[dd].config.isTarget){
56157 dds[dd].proxyTop.remove();
56158 dds[dd].proxyBottom.remove();
56161 if(Roo.dd.DDM.locationCache[dd]){
56162 delete Roo.dd.DDM.locationCache[dd];
56165 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56168 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56169 this.bind(null, null);
56170 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56173 handleLockChange : function(){
56174 this.refresh(true);
56177 onDenyColumnLock : function(){
56181 onDenyColumnHide : function(){
56185 handleHdMenuClick : function(item){
56186 var index = this.hdCtxIndex;
56187 var cm = this.cm, ds = this.ds;
56190 ds.sort(cm.getDataIndex(index), "ASC");
56193 ds.sort(cm.getDataIndex(index), "DESC");
56196 var lc = cm.getLockedCount();
56197 if(cm.getColumnCount(true) <= lc+1){
56198 this.onDenyColumnLock();
56202 cm.setLocked(index, true, true);
56203 cm.moveColumn(index, lc);
56204 this.grid.fireEvent("columnmove", index, lc);
56206 cm.setLocked(index, true);
56210 var lc = cm.getLockedCount();
56211 if((lc-1) != index){
56212 cm.setLocked(index, false, true);
56213 cm.moveColumn(index, lc-1);
56214 this.grid.fireEvent("columnmove", index, lc-1);
56216 cm.setLocked(index, false);
56219 case 'wider': // used to expand cols on touch..
56221 var cw = cm.getColumnWidth(index);
56222 cw += (item.id == 'wider' ? 1 : -1) * 50;
56223 cw = Math.max(0, cw);
56224 cw = Math.min(cw,4000);
56225 cm.setColumnWidth(index, cw);
56229 index = cm.getIndexById(item.id.substr(4));
56231 if(item.checked && cm.getColumnCount(true) <= 1){
56232 this.onDenyColumnHide();
56235 cm.setHidden(index, item.checked);
56241 beforeColMenuShow : function(){
56242 var cm = this.cm, colCount = cm.getColumnCount();
56243 this.colMenu.removeAll();
56244 for(var i = 0; i < colCount; i++){
56245 this.colMenu.add(new Roo.menu.CheckItem({
56246 id: "col-"+cm.getColumnId(i),
56247 text: cm.getColumnHeader(i),
56248 checked: !cm.isHidden(i),
56254 handleHdCtx : function(g, index, e){
56256 var hd = this.getHeaderCell(index);
56257 this.hdCtxIndex = index;
56258 var ms = this.hmenu.items, cm = this.cm;
56259 ms.get("asc").setDisabled(!cm.isSortable(index));
56260 ms.get("desc").setDisabled(!cm.isSortable(index));
56261 if(this.grid.enableColLock !== false){
56262 ms.get("lock").setDisabled(cm.isLocked(index));
56263 ms.get("unlock").setDisabled(!cm.isLocked(index));
56265 this.hmenu.show(hd, "tl-bl");
56268 handleHdOver : function(e){
56269 var hd = this.findHeaderCell(e.getTarget());
56270 if(hd && !this.headersDisabled){
56271 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56272 this.fly(hd).addClass("x-grid-hd-over");
56277 handleHdOut : function(e){
56278 var hd = this.findHeaderCell(e.getTarget());
56280 this.fly(hd).removeClass("x-grid-hd-over");
56284 handleSplitDblClick : function(e, t){
56285 var i = this.getCellIndex(t);
56286 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56287 this.autoSizeColumn(i, true);
56292 render : function(){
56295 var colCount = cm.getColumnCount();
56297 if(this.grid.monitorWindowResize === true){
56298 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56300 var header = this.renderHeaders();
56301 var body = this.templates.body.apply({rows:""});
56302 var html = this.templates.master.apply({
56305 lockedHeader: header[0],
56309 //this.updateColumns();
56311 this.grid.getGridEl().dom.innerHTML = html;
56313 this.initElements();
56315 // a kludge to fix the random scolling effect in webkit
56316 this.el.on("scroll", function() {
56317 this.el.dom.scrollTop=0; // hopefully not recursive..
56320 this.scroller.on("scroll", this.handleScroll, this);
56321 this.lockedBody.on("mousewheel", this.handleWheel, this);
56322 this.mainBody.on("mousewheel", this.handleWheel, this);
56324 this.mainHd.on("mouseover", this.handleHdOver, this);
56325 this.mainHd.on("mouseout", this.handleHdOut, this);
56326 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56327 {delegate: "."+this.splitClass});
56329 this.lockedHd.on("mouseover", this.handleHdOver, this);
56330 this.lockedHd.on("mouseout", this.handleHdOut, this);
56331 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56332 {delegate: "."+this.splitClass});
56334 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56335 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56338 this.updateSplitters();
56340 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56341 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56342 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56345 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56346 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56348 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56349 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56351 if(this.grid.enableColLock !== false){
56352 this.hmenu.add('-',
56353 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56354 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56358 this.hmenu.add('-',
56359 {id:"wider", text: this.columnsWiderText},
56360 {id:"narrow", text: this.columnsNarrowText }
56366 if(this.grid.enableColumnHide !== false){
56368 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56369 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56370 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56372 this.hmenu.add('-',
56373 {id:"columns", text: this.columnsText, menu: this.colMenu}
56376 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56378 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56381 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56382 this.dd = new Roo.grid.GridDragZone(this.grid, {
56383 ddGroup : this.grid.ddGroup || 'GridDD'
56389 for(var i = 0; i < colCount; i++){
56390 if(cm.isHidden(i)){
56391 this.hideColumn(i);
56393 if(cm.config[i].align){
56394 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56395 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56399 this.updateHeaderSortState();
56401 this.beforeInitialResize();
56404 // two part rendering gives faster view to the user
56405 this.renderPhase2.defer(1, this);
56408 renderPhase2 : function(){
56409 // render the rows now
56411 if(this.grid.autoSizeColumns){
56412 this.autoSizeColumns();
56416 beforeInitialResize : function(){
56420 onColumnSplitterMoved : function(i, w){
56421 this.userResized = true;
56422 var cm = this.grid.colModel;
56423 cm.setColumnWidth(i, w, true);
56424 var cid = cm.getColumnId(i);
56425 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56426 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56427 this.updateSplitters();
56429 this.grid.fireEvent("columnresize", i, w);
56432 syncRowHeights : function(startIndex, endIndex){
56433 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56434 startIndex = startIndex || 0;
56435 var mrows = this.getBodyTable().rows;
56436 var lrows = this.getLockedTable().rows;
56437 var len = mrows.length-1;
56438 endIndex = Math.min(endIndex || len, len);
56439 for(var i = startIndex; i <= endIndex; i++){
56440 var m = mrows[i], l = lrows[i];
56441 var h = Math.max(m.offsetHeight, l.offsetHeight);
56442 m.style.height = l.style.height = h + "px";
56447 layout : function(initialRender, is2ndPass){
56449 var auto = g.autoHeight;
56450 var scrollOffset = 16;
56451 var c = g.getGridEl(), cm = this.cm,
56452 expandCol = g.autoExpandColumn,
56454 //c.beginMeasure();
56456 if(!c.dom.offsetWidth){ // display:none?
56458 this.lockedWrap.show();
56459 this.mainWrap.show();
56464 var hasLock = this.cm.isLocked(0);
56466 var tbh = this.headerPanel.getHeight();
56467 var bbh = this.footerPanel.getHeight();
56470 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56471 var newHeight = ch + c.getBorderWidth("tb");
56473 newHeight = Math.min(g.maxHeight, newHeight);
56475 c.setHeight(newHeight);
56479 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56482 var s = this.scroller;
56484 var csize = c.getSize(true);
56486 this.el.setSize(csize.width, csize.height);
56488 this.headerPanel.setWidth(csize.width);
56489 this.footerPanel.setWidth(csize.width);
56491 var hdHeight = this.mainHd.getHeight();
56492 var vw = csize.width;
56493 var vh = csize.height - (tbh + bbh);
56497 var bt = this.getBodyTable();
56499 if(cm.getLockedCount() == cm.config.length){
56500 bt = this.getLockedTable();
56503 var ltWidth = hasLock ?
56504 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56506 var scrollHeight = bt.offsetHeight;
56507 var scrollWidth = ltWidth + bt.offsetWidth;
56508 var vscroll = false, hscroll = false;
56510 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56512 var lw = this.lockedWrap, mw = this.mainWrap;
56513 var lb = this.lockedBody, mb = this.mainBody;
56515 setTimeout(function(){
56516 var t = s.dom.offsetTop;
56517 var w = s.dom.clientWidth,
56518 h = s.dom.clientHeight;
56521 lw.setSize(ltWidth, h);
56523 mw.setLeftTop(ltWidth, t);
56524 mw.setSize(w-ltWidth, h);
56526 lb.setHeight(h-hdHeight);
56527 mb.setHeight(h-hdHeight);
56529 if(is2ndPass !== true && !gv.userResized && expandCol){
56530 // high speed resize without full column calculation
56532 var ci = cm.getIndexById(expandCol);
56534 ci = cm.findColumnIndex(expandCol);
56536 ci = Math.max(0, ci); // make sure it's got at least the first col.
56537 var expandId = cm.getColumnId(ci);
56538 var tw = cm.getTotalWidth(false);
56539 var currentWidth = cm.getColumnWidth(ci);
56540 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56541 if(currentWidth != cw){
56542 cm.setColumnWidth(ci, cw, true);
56543 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56544 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56545 gv.updateSplitters();
56546 gv.layout(false, true);
56558 onWindowResize : function(){
56559 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56565 appendFooter : function(parentEl){
56569 sortAscText : "Sort Ascending",
56570 sortDescText : "Sort Descending",
56571 lockText : "Lock Column",
56572 unlockText : "Unlock Column",
56573 columnsText : "Columns",
56575 columnsWiderText : "Wider",
56576 columnsNarrowText : "Thinner"
56580 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56581 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56582 this.proxy.el.addClass('x-grid3-col-dd');
56585 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56586 handleMouseDown : function(e){
56590 callHandleMouseDown : function(e){
56591 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56596 * Ext JS Library 1.1.1
56597 * Copyright(c) 2006-2007, Ext JS, LLC.
56599 * Originally Released Under LGPL - original licence link has changed is not relivant.
56602 * <script type="text/javascript">
56606 // This is a support class used internally by the Grid components
56607 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56609 this.view = grid.getView();
56610 this.proxy = this.view.resizeProxy;
56611 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56612 "gridSplitters" + this.grid.getGridEl().id, {
56613 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56615 this.setHandleElId(Roo.id(hd));
56616 this.setOuterHandleElId(Roo.id(hd2));
56617 this.scroll = false;
56619 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56620 fly: Roo.Element.fly,
56622 b4StartDrag : function(x, y){
56623 this.view.headersDisabled = true;
56624 this.proxy.setHeight(this.view.mainWrap.getHeight());
56625 var w = this.cm.getColumnWidth(this.cellIndex);
56626 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56627 this.resetConstraints();
56628 this.setXConstraint(minw, 1000);
56629 this.setYConstraint(0, 0);
56630 this.minX = x - minw;
56631 this.maxX = x + 1000;
56633 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56637 handleMouseDown : function(e){
56638 ev = Roo.EventObject.setEvent(e);
56639 var t = this.fly(ev.getTarget());
56640 if(t.hasClass("x-grid-split")){
56641 this.cellIndex = this.view.getCellIndex(t.dom);
56642 this.split = t.dom;
56643 this.cm = this.grid.colModel;
56644 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56645 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56650 endDrag : function(e){
56651 this.view.headersDisabled = false;
56652 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56653 var diff = endX - this.startPos;
56654 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56657 autoOffset : function(){
56658 this.setDelta(0,0);
56662 * Ext JS Library 1.1.1
56663 * Copyright(c) 2006-2007, Ext JS, LLC.
56665 * Originally Released Under LGPL - original licence link has changed is not relivant.
56668 * <script type="text/javascript">
56672 // This is a support class used internally by the Grid components
56673 Roo.grid.GridDragZone = function(grid, config){
56674 this.view = grid.getView();
56675 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56676 if(this.view.lockedBody){
56677 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56678 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56680 this.scroll = false;
56682 this.ddel = document.createElement('div');
56683 this.ddel.className = 'x-grid-dd-wrap';
56686 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56687 ddGroup : "GridDD",
56689 getDragData : function(e){
56690 var t = Roo.lib.Event.getTarget(e);
56691 var rowIndex = this.view.findRowIndex(t);
56692 var sm = this.grid.selModel;
56694 //Roo.log(rowIndex);
56696 if (sm.getSelectedCell) {
56697 // cell selection..
56698 if (!sm.getSelectedCell()) {
56701 if (rowIndex != sm.getSelectedCell()[0]) {
56707 if(rowIndex !== false){
56712 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56714 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56717 if (e.hasModifier()){
56718 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56721 Roo.log("getDragData");
56726 rowIndex: rowIndex,
56727 selections:sm.getSelections ? sm.getSelections() : (
56728 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56735 onInitDrag : function(e){
56736 var data = this.dragData;
56737 this.ddel.innerHTML = this.grid.getDragDropText();
56738 this.proxy.update(this.ddel);
56739 // fire start drag?
56742 afterRepair : function(){
56743 this.dragging = false;
56746 getRepairXY : function(e, data){
56750 onEndDrag : function(data, e){
56754 onValidDrop : function(dd, e, id){
56759 beforeInvalidDrop : function(e, id){
56764 * Ext JS Library 1.1.1
56765 * Copyright(c) 2006-2007, Ext JS, LLC.
56767 * Originally Released Under LGPL - original licence link has changed is not relivant.
56770 * <script type="text/javascript">
56775 * @class Roo.grid.ColumnModel
56776 * @extends Roo.util.Observable
56777 * This is the default implementation of a ColumnModel used by the Grid. It defines
56778 * the columns in the grid.
56781 var colModel = new Roo.grid.ColumnModel([
56782 {header: "Ticker", width: 60, sortable: true, locked: true},
56783 {header: "Company Name", width: 150, sortable: true},
56784 {header: "Market Cap.", width: 100, sortable: true},
56785 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56786 {header: "Employees", width: 100, sortable: true, resizable: false}
56791 * The config options listed for this class are options which may appear in each
56792 * individual column definition.
56793 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56795 * @param {Object} config An Array of column config objects. See this class's
56796 * config objects for details.
56798 Roo.grid.ColumnModel = function(config){
56800 * The config passed into the constructor
56802 this.config = config;
56805 // if no id, create one
56806 // if the column does not have a dataIndex mapping,
56807 // map it to the order it is in the config
56808 for(var i = 0, len = config.length; i < len; i++){
56810 if(typeof c.dataIndex == "undefined"){
56813 if(typeof c.renderer == "string"){
56814 c.renderer = Roo.util.Format[c.renderer];
56816 if(typeof c.id == "undefined"){
56819 if(c.editor && c.editor.xtype){
56820 c.editor = Roo.factory(c.editor, Roo.grid);
56822 if(c.editor && c.editor.isFormField){
56823 c.editor = new Roo.grid.GridEditor(c.editor);
56825 this.lookup[c.id] = c;
56829 * The width of columns which have no width specified (defaults to 100)
56832 this.defaultWidth = 100;
56835 * Default sortable of columns which have no sortable specified (defaults to false)
56838 this.defaultSortable = false;
56842 * @event widthchange
56843 * Fires when the width of a column changes.
56844 * @param {ColumnModel} this
56845 * @param {Number} columnIndex The column index
56846 * @param {Number} newWidth The new width
56848 "widthchange": true,
56850 * @event headerchange
56851 * Fires when the text of a header changes.
56852 * @param {ColumnModel} this
56853 * @param {Number} columnIndex The column index
56854 * @param {Number} newText The new header text
56856 "headerchange": true,
56858 * @event hiddenchange
56859 * Fires when a column is hidden or "unhidden".
56860 * @param {ColumnModel} this
56861 * @param {Number} columnIndex The column index
56862 * @param {Boolean} hidden true if hidden, false otherwise
56864 "hiddenchange": true,
56866 * @event columnmoved
56867 * Fires when a column is moved.
56868 * @param {ColumnModel} this
56869 * @param {Number} oldIndex
56870 * @param {Number} newIndex
56872 "columnmoved" : true,
56874 * @event columlockchange
56875 * Fires when a column's locked state is changed
56876 * @param {ColumnModel} this
56877 * @param {Number} colIndex
56878 * @param {Boolean} locked true if locked
56880 "columnlockchange" : true
56882 Roo.grid.ColumnModel.superclass.constructor.call(this);
56884 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
56886 * @cfg {String} header The header text to display in the Grid view.
56889 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
56890 * {@link Roo.data.Record} definition from which to draw the column's value. If not
56891 * specified, the column's index is used as an index into the Record's data Array.
56894 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
56895 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
56898 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
56899 * Defaults to the value of the {@link #defaultSortable} property.
56900 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
56903 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
56906 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
56909 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
56912 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
56915 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
56916 * given the cell's data value. See {@link #setRenderer}. If not specified, the
56917 * default renderer uses the raw data value. If an object is returned (bootstrap only)
56918 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
56921 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
56924 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
56927 * @cfg {String} cursor (Optional)
56930 * @cfg {String} tooltip (Optional)
56933 * @cfg {Number} xs (Optional)
56936 * @cfg {Number} sm (Optional)
56939 * @cfg {Number} md (Optional)
56942 * @cfg {Number} lg (Optional)
56945 * Returns the id of the column at the specified index.
56946 * @param {Number} index The column index
56947 * @return {String} the id
56949 getColumnId : function(index){
56950 return this.config[index].id;
56954 * Returns the column for a specified id.
56955 * @param {String} id The column id
56956 * @return {Object} the column
56958 getColumnById : function(id){
56959 return this.lookup[id];
56964 * Returns the column for a specified dataIndex.
56965 * @param {String} dataIndex The column dataIndex
56966 * @return {Object|Boolean} the column or false if not found
56968 getColumnByDataIndex: function(dataIndex){
56969 var index = this.findColumnIndex(dataIndex);
56970 return index > -1 ? this.config[index] : false;
56974 * Returns the index for a specified column id.
56975 * @param {String} id The column id
56976 * @return {Number} the index, or -1 if not found
56978 getIndexById : function(id){
56979 for(var i = 0, len = this.config.length; i < len; i++){
56980 if(this.config[i].id == id){
56988 * Returns the index for a specified column dataIndex.
56989 * @param {String} dataIndex The column dataIndex
56990 * @return {Number} the index, or -1 if not found
56993 findColumnIndex : function(dataIndex){
56994 for(var i = 0, len = this.config.length; i < len; i++){
56995 if(this.config[i].dataIndex == dataIndex){
57003 moveColumn : function(oldIndex, newIndex){
57004 var c = this.config[oldIndex];
57005 this.config.splice(oldIndex, 1);
57006 this.config.splice(newIndex, 0, c);
57007 this.dataMap = null;
57008 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57011 isLocked : function(colIndex){
57012 return this.config[colIndex].locked === true;
57015 setLocked : function(colIndex, value, suppressEvent){
57016 if(this.isLocked(colIndex) == value){
57019 this.config[colIndex].locked = value;
57020 if(!suppressEvent){
57021 this.fireEvent("columnlockchange", this, colIndex, value);
57025 getTotalLockedWidth : function(){
57026 var totalWidth = 0;
57027 for(var i = 0; i < this.config.length; i++){
57028 if(this.isLocked(i) && !this.isHidden(i)){
57029 this.totalWidth += this.getColumnWidth(i);
57035 getLockedCount : function(){
57036 for(var i = 0, len = this.config.length; i < len; i++){
57037 if(!this.isLocked(i)){
57042 return this.config.length;
57046 * Returns the number of columns.
57049 getColumnCount : function(visibleOnly){
57050 if(visibleOnly === true){
57052 for(var i = 0, len = this.config.length; i < len; i++){
57053 if(!this.isHidden(i)){
57059 return this.config.length;
57063 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57064 * @param {Function} fn
57065 * @param {Object} scope (optional)
57066 * @return {Array} result
57068 getColumnsBy : function(fn, scope){
57070 for(var i = 0, len = this.config.length; i < len; i++){
57071 var c = this.config[i];
57072 if(fn.call(scope||this, c, i) === true){
57080 * Returns true if the specified column is sortable.
57081 * @param {Number} col The column index
57082 * @return {Boolean}
57084 isSortable : function(col){
57085 if(typeof this.config[col].sortable == "undefined"){
57086 return this.defaultSortable;
57088 return this.config[col].sortable;
57092 * Returns the rendering (formatting) function defined for the column.
57093 * @param {Number} col The column index.
57094 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57096 getRenderer : function(col){
57097 if(!this.config[col].renderer){
57098 return Roo.grid.ColumnModel.defaultRenderer;
57100 return this.config[col].renderer;
57104 * Sets the rendering (formatting) function for a column.
57105 * @param {Number} col The column index
57106 * @param {Function} fn The function to use to process the cell's raw data
57107 * to return HTML markup for the grid view. The render function is called with
57108 * the following parameters:<ul>
57109 * <li>Data value.</li>
57110 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57111 * <li>css A CSS style string to apply to the table cell.</li>
57112 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57113 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57114 * <li>Row index</li>
57115 * <li>Column index</li>
57116 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57118 setRenderer : function(col, fn){
57119 this.config[col].renderer = fn;
57123 * Returns the width for the specified column.
57124 * @param {Number} col The column index
57127 getColumnWidth : function(col){
57128 return this.config[col].width * 1 || this.defaultWidth;
57132 * Sets the width for a column.
57133 * @param {Number} col The column index
57134 * @param {Number} width The new width
57136 setColumnWidth : function(col, width, suppressEvent){
57137 this.config[col].width = width;
57138 this.totalWidth = null;
57139 if(!suppressEvent){
57140 this.fireEvent("widthchange", this, col, width);
57145 * Returns the total width of all columns.
57146 * @param {Boolean} includeHidden True to include hidden column widths
57149 getTotalWidth : function(includeHidden){
57150 if(!this.totalWidth){
57151 this.totalWidth = 0;
57152 for(var i = 0, len = this.config.length; i < len; i++){
57153 if(includeHidden || !this.isHidden(i)){
57154 this.totalWidth += this.getColumnWidth(i);
57158 return this.totalWidth;
57162 * Returns the header for the specified column.
57163 * @param {Number} col The column index
57166 getColumnHeader : function(col){
57167 return this.config[col].header;
57171 * Sets the header for a column.
57172 * @param {Number} col The column index
57173 * @param {String} header The new header
57175 setColumnHeader : function(col, header){
57176 this.config[col].header = header;
57177 this.fireEvent("headerchange", this, col, header);
57181 * Returns the tooltip for the specified column.
57182 * @param {Number} col The column index
57185 getColumnTooltip : function(col){
57186 return this.config[col].tooltip;
57189 * Sets the tooltip for a column.
57190 * @param {Number} col The column index
57191 * @param {String} tooltip The new tooltip
57193 setColumnTooltip : function(col, tooltip){
57194 this.config[col].tooltip = tooltip;
57198 * Returns the dataIndex for the specified column.
57199 * @param {Number} col The column index
57202 getDataIndex : function(col){
57203 return this.config[col].dataIndex;
57207 * Sets the dataIndex for a column.
57208 * @param {Number} col The column index
57209 * @param {Number} dataIndex The new dataIndex
57211 setDataIndex : function(col, dataIndex){
57212 this.config[col].dataIndex = dataIndex;
57218 * Returns true if the cell is editable.
57219 * @param {Number} colIndex The column index
57220 * @param {Number} rowIndex The row index - this is nto actually used..?
57221 * @return {Boolean}
57223 isCellEditable : function(colIndex, rowIndex){
57224 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57228 * Returns the editor defined for the cell/column.
57229 * return false or null to disable editing.
57230 * @param {Number} colIndex The column index
57231 * @param {Number} rowIndex The row index
57234 getCellEditor : function(colIndex, rowIndex){
57235 return this.config[colIndex].editor;
57239 * Sets if a column is editable.
57240 * @param {Number} col The column index
57241 * @param {Boolean} editable True if the column is editable
57243 setEditable : function(col, editable){
57244 this.config[col].editable = editable;
57249 * Returns true if the column is hidden.
57250 * @param {Number} colIndex The column index
57251 * @return {Boolean}
57253 isHidden : function(colIndex){
57254 return this.config[colIndex].hidden;
57259 * Returns true if the column width cannot be changed
57261 isFixed : function(colIndex){
57262 return this.config[colIndex].fixed;
57266 * Returns true if the column can be resized
57267 * @return {Boolean}
57269 isResizable : function(colIndex){
57270 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57273 * Sets if a column is hidden.
57274 * @param {Number} colIndex The column index
57275 * @param {Boolean} hidden True if the column is hidden
57277 setHidden : function(colIndex, hidden){
57278 this.config[colIndex].hidden = hidden;
57279 this.totalWidth = null;
57280 this.fireEvent("hiddenchange", this, colIndex, hidden);
57284 * Sets the editor for a column.
57285 * @param {Number} col The column index
57286 * @param {Object} editor The editor object
57288 setEditor : function(col, editor){
57289 this.config[col].editor = editor;
57293 Roo.grid.ColumnModel.defaultRenderer = function(value){
57294 if(typeof value == "string" && value.length < 1){
57300 // Alias for backwards compatibility
57301 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57304 * Ext JS Library 1.1.1
57305 * Copyright(c) 2006-2007, Ext JS, LLC.
57307 * Originally Released Under LGPL - original licence link has changed is not relivant.
57310 * <script type="text/javascript">
57314 * @class Roo.grid.AbstractSelectionModel
57315 * @extends Roo.util.Observable
57316 * Abstract base class for grid SelectionModels. It provides the interface that should be
57317 * implemented by descendant classes. This class should not be directly instantiated.
57320 Roo.grid.AbstractSelectionModel = function(){
57321 this.locked = false;
57322 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57325 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57326 /** @ignore Called by the grid automatically. Do not call directly. */
57327 init : function(grid){
57333 * Locks the selections.
57336 this.locked = true;
57340 * Unlocks the selections.
57342 unlock : function(){
57343 this.locked = false;
57347 * Returns true if the selections are locked.
57348 * @return {Boolean}
57350 isLocked : function(){
57351 return this.locked;
57355 * Ext JS Library 1.1.1
57356 * Copyright(c) 2006-2007, Ext JS, LLC.
57358 * Originally Released Under LGPL - original licence link has changed is not relivant.
57361 * <script type="text/javascript">
57364 * @extends Roo.grid.AbstractSelectionModel
57365 * @class Roo.grid.RowSelectionModel
57366 * The default SelectionModel used by {@link Roo.grid.Grid}.
57367 * It supports multiple selections and keyboard selection/navigation.
57369 * @param {Object} config
57371 Roo.grid.RowSelectionModel = function(config){
57372 Roo.apply(this, config);
57373 this.selections = new Roo.util.MixedCollection(false, function(o){
57378 this.lastActive = false;
57382 * @event selectionchange
57383 * Fires when the selection changes
57384 * @param {SelectionModel} this
57386 "selectionchange" : true,
57388 * @event afterselectionchange
57389 * Fires after the selection changes (eg. by key press or clicking)
57390 * @param {SelectionModel} this
57392 "afterselectionchange" : true,
57394 * @event beforerowselect
57395 * Fires when a row is selected being selected, return false to cancel.
57396 * @param {SelectionModel} this
57397 * @param {Number} rowIndex The selected index
57398 * @param {Boolean} keepExisting False if other selections will be cleared
57400 "beforerowselect" : true,
57403 * Fires when a row is selected.
57404 * @param {SelectionModel} this
57405 * @param {Number} rowIndex The selected index
57406 * @param {Roo.data.Record} r The record
57408 "rowselect" : true,
57410 * @event rowdeselect
57411 * Fires when a row is deselected.
57412 * @param {SelectionModel} this
57413 * @param {Number} rowIndex The selected index
57415 "rowdeselect" : true
57417 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57418 this.locked = false;
57421 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57423 * @cfg {Boolean} singleSelect
57424 * True to allow selection of only one row at a time (defaults to false)
57426 singleSelect : false,
57429 initEvents : function(){
57431 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57432 this.grid.on("mousedown", this.handleMouseDown, this);
57433 }else{ // allow click to work like normal
57434 this.grid.on("rowclick", this.handleDragableRowClick, this);
57437 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57438 "up" : function(e){
57440 this.selectPrevious(e.shiftKey);
57441 }else if(this.last !== false && this.lastActive !== false){
57442 var last = this.last;
57443 this.selectRange(this.last, this.lastActive-1);
57444 this.grid.getView().focusRow(this.lastActive);
57445 if(last !== false){
57449 this.selectFirstRow();
57451 this.fireEvent("afterselectionchange", this);
57453 "down" : function(e){
57455 this.selectNext(e.shiftKey);
57456 }else if(this.last !== false && this.lastActive !== false){
57457 var last = this.last;
57458 this.selectRange(this.last, this.lastActive+1);
57459 this.grid.getView().focusRow(this.lastActive);
57460 if(last !== false){
57464 this.selectFirstRow();
57466 this.fireEvent("afterselectionchange", this);
57471 var view = this.grid.view;
57472 view.on("refresh", this.onRefresh, this);
57473 view.on("rowupdated", this.onRowUpdated, this);
57474 view.on("rowremoved", this.onRemove, this);
57478 onRefresh : function(){
57479 var ds = this.grid.dataSource, i, v = this.grid.view;
57480 var s = this.selections;
57481 s.each(function(r){
57482 if((i = ds.indexOfId(r.id)) != -1){
57484 s.add(ds.getAt(i)); // updating the selection relate data
57492 onRemove : function(v, index, r){
57493 this.selections.remove(r);
57497 onRowUpdated : function(v, index, r){
57498 if(this.isSelected(r)){
57499 v.onRowSelect(index);
57505 * @param {Array} records The records to select
57506 * @param {Boolean} keepExisting (optional) True to keep existing selections
57508 selectRecords : function(records, keepExisting){
57510 this.clearSelections();
57512 var ds = this.grid.dataSource;
57513 for(var i = 0, len = records.length; i < len; i++){
57514 this.selectRow(ds.indexOf(records[i]), true);
57519 * Gets the number of selected rows.
57522 getCount : function(){
57523 return this.selections.length;
57527 * Selects the first row in the grid.
57529 selectFirstRow : function(){
57534 * Select the last row.
57535 * @param {Boolean} keepExisting (optional) True to keep existing selections
57537 selectLastRow : function(keepExisting){
57538 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57542 * Selects the row immediately following the last selected row.
57543 * @param {Boolean} keepExisting (optional) True to keep existing selections
57545 selectNext : function(keepExisting){
57546 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57547 this.selectRow(this.last+1, keepExisting);
57548 this.grid.getView().focusRow(this.last);
57553 * Selects the row that precedes the last selected row.
57554 * @param {Boolean} keepExisting (optional) True to keep existing selections
57556 selectPrevious : function(keepExisting){
57558 this.selectRow(this.last-1, keepExisting);
57559 this.grid.getView().focusRow(this.last);
57564 * Returns the selected records
57565 * @return {Array} Array of selected records
57567 getSelections : function(){
57568 return [].concat(this.selections.items);
57572 * Returns the first selected record.
57575 getSelected : function(){
57576 return this.selections.itemAt(0);
57581 * Clears all selections.
57583 clearSelections : function(fast){
57588 var ds = this.grid.dataSource;
57589 var s = this.selections;
57590 s.each(function(r){
57591 this.deselectRow(ds.indexOfId(r.id));
57595 this.selections.clear();
57602 * Selects all rows.
57604 selectAll : function(){
57608 this.selections.clear();
57609 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57610 this.selectRow(i, true);
57615 * Returns True if there is a selection.
57616 * @return {Boolean}
57618 hasSelection : function(){
57619 return this.selections.length > 0;
57623 * Returns True if the specified row is selected.
57624 * @param {Number/Record} record The record or index of the record to check
57625 * @return {Boolean}
57627 isSelected : function(index){
57628 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57629 return (r && this.selections.key(r.id) ? true : false);
57633 * Returns True if the specified record id is selected.
57634 * @param {String} id The id of record to check
57635 * @return {Boolean}
57637 isIdSelected : function(id){
57638 return (this.selections.key(id) ? true : false);
57642 handleMouseDown : function(e, t){
57643 var view = this.grid.getView(), rowIndex;
57644 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57647 if(e.shiftKey && this.last !== false){
57648 var last = this.last;
57649 this.selectRange(last, rowIndex, e.ctrlKey);
57650 this.last = last; // reset the last
57651 view.focusRow(rowIndex);
57653 var isSelected = this.isSelected(rowIndex);
57654 if(e.button !== 0 && isSelected){
57655 view.focusRow(rowIndex);
57656 }else if(e.ctrlKey && isSelected){
57657 this.deselectRow(rowIndex);
57658 }else if(!isSelected){
57659 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57660 view.focusRow(rowIndex);
57663 this.fireEvent("afterselectionchange", this);
57666 handleDragableRowClick : function(grid, rowIndex, e)
57668 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57669 this.selectRow(rowIndex, false);
57670 grid.view.focusRow(rowIndex);
57671 this.fireEvent("afterselectionchange", this);
57676 * Selects multiple rows.
57677 * @param {Array} rows Array of the indexes of the row to select
57678 * @param {Boolean} keepExisting (optional) True to keep existing selections
57680 selectRows : function(rows, keepExisting){
57682 this.clearSelections();
57684 for(var i = 0, len = rows.length; i < len; i++){
57685 this.selectRow(rows[i], true);
57690 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57691 * @param {Number} startRow The index of the first row in the range
57692 * @param {Number} endRow The index of the last row in the range
57693 * @param {Boolean} keepExisting (optional) True to retain existing selections
57695 selectRange : function(startRow, endRow, keepExisting){
57700 this.clearSelections();
57702 if(startRow <= endRow){
57703 for(var i = startRow; i <= endRow; i++){
57704 this.selectRow(i, true);
57707 for(var i = startRow; i >= endRow; i--){
57708 this.selectRow(i, true);
57714 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57715 * @param {Number} startRow The index of the first row in the range
57716 * @param {Number} endRow The index of the last row in the range
57718 deselectRange : function(startRow, endRow, preventViewNotify){
57722 for(var i = startRow; i <= endRow; i++){
57723 this.deselectRow(i, preventViewNotify);
57729 * @param {Number} row The index of the row to select
57730 * @param {Boolean} keepExisting (optional) True to keep existing selections
57732 selectRow : function(index, keepExisting, preventViewNotify){
57733 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57736 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57737 if(!keepExisting || this.singleSelect){
57738 this.clearSelections();
57740 var r = this.grid.dataSource.getAt(index);
57741 this.selections.add(r);
57742 this.last = this.lastActive = index;
57743 if(!preventViewNotify){
57744 this.grid.getView().onRowSelect(index);
57746 this.fireEvent("rowselect", this, index, r);
57747 this.fireEvent("selectionchange", this);
57753 * @param {Number} row The index of the row to deselect
57755 deselectRow : function(index, preventViewNotify){
57759 if(this.last == index){
57762 if(this.lastActive == index){
57763 this.lastActive = false;
57765 var r = this.grid.dataSource.getAt(index);
57766 this.selections.remove(r);
57767 if(!preventViewNotify){
57768 this.grid.getView().onRowDeselect(index);
57770 this.fireEvent("rowdeselect", this, index);
57771 this.fireEvent("selectionchange", this);
57775 restoreLast : function(){
57777 this.last = this._last;
57782 acceptsNav : function(row, col, cm){
57783 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57787 onEditorKey : function(field, e){
57788 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57793 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57795 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57797 }else if(k == e.ENTER && !e.ctrlKey){
57801 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57803 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57805 }else if(k == e.ESC){
57809 g.startEditing(newCell[0], newCell[1]);
57814 * Ext JS Library 1.1.1
57815 * Copyright(c) 2006-2007, Ext JS, LLC.
57817 * Originally Released Under LGPL - original licence link has changed is not relivant.
57820 * <script type="text/javascript">
57823 * @class Roo.grid.CellSelectionModel
57824 * @extends Roo.grid.AbstractSelectionModel
57825 * This class provides the basic implementation for cell selection in a grid.
57827 * @param {Object} config The object containing the configuration of this model.
57828 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57830 Roo.grid.CellSelectionModel = function(config){
57831 Roo.apply(this, config);
57833 this.selection = null;
57837 * @event beforerowselect
57838 * Fires before a cell is selected.
57839 * @param {SelectionModel} this
57840 * @param {Number} rowIndex The selected row index
57841 * @param {Number} colIndex The selected cell index
57843 "beforecellselect" : true,
57845 * @event cellselect
57846 * Fires when a cell is selected.
57847 * @param {SelectionModel} this
57848 * @param {Number} rowIndex The selected row index
57849 * @param {Number} colIndex The selected cell index
57851 "cellselect" : true,
57853 * @event selectionchange
57854 * Fires when the active selection changes.
57855 * @param {SelectionModel} this
57856 * @param {Object} selection null for no selection or an object (o) with two properties
57858 <li>o.record: the record object for the row the selection is in</li>
57859 <li>o.cell: An array of [rowIndex, columnIndex]</li>
57862 "selectionchange" : true,
57865 * Fires when the tab (or enter) was pressed on the last editable cell
57866 * You can use this to trigger add new row.
57867 * @param {SelectionModel} this
57871 * @event beforeeditnext
57872 * Fires before the next editable sell is made active
57873 * You can use this to skip to another cell or fire the tabend
57874 * if you set cell to false
57875 * @param {Object} eventdata object : { cell : [ row, col ] }
57877 "beforeeditnext" : true
57879 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
57882 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
57884 enter_is_tab: false,
57887 initEvents : function(){
57888 this.grid.on("mousedown", this.handleMouseDown, this);
57889 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
57890 var view = this.grid.view;
57891 view.on("refresh", this.onViewChange, this);
57892 view.on("rowupdated", this.onRowUpdated, this);
57893 view.on("beforerowremoved", this.clearSelections, this);
57894 view.on("beforerowsinserted", this.clearSelections, this);
57895 if(this.grid.isEditor){
57896 this.grid.on("beforeedit", this.beforeEdit, this);
57901 beforeEdit : function(e){
57902 this.select(e.row, e.column, false, true, e.record);
57906 onRowUpdated : function(v, index, r){
57907 if(this.selection && this.selection.record == r){
57908 v.onCellSelect(index, this.selection.cell[1]);
57913 onViewChange : function(){
57914 this.clearSelections(true);
57918 * Returns the currently selected cell,.
57919 * @return {Array} The selected cell (row, column) or null if none selected.
57921 getSelectedCell : function(){
57922 return this.selection ? this.selection.cell : null;
57926 * Clears all selections.
57927 * @param {Boolean} true to prevent the gridview from being notified about the change.
57929 clearSelections : function(preventNotify){
57930 var s = this.selection;
57932 if(preventNotify !== true){
57933 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
57935 this.selection = null;
57936 this.fireEvent("selectionchange", this, null);
57941 * Returns true if there is a selection.
57942 * @return {Boolean}
57944 hasSelection : function(){
57945 return this.selection ? true : false;
57949 handleMouseDown : function(e, t){
57950 var v = this.grid.getView();
57951 if(this.isLocked()){
57954 var row = v.findRowIndex(t);
57955 var cell = v.findCellIndex(t);
57956 if(row !== false && cell !== false){
57957 this.select(row, cell);
57963 * @param {Number} rowIndex
57964 * @param {Number} collIndex
57966 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
57967 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
57968 this.clearSelections();
57969 r = r || this.grid.dataSource.getAt(rowIndex);
57972 cell : [rowIndex, colIndex]
57974 if(!preventViewNotify){
57975 var v = this.grid.getView();
57976 v.onCellSelect(rowIndex, colIndex);
57977 if(preventFocus !== true){
57978 v.focusCell(rowIndex, colIndex);
57981 this.fireEvent("cellselect", this, rowIndex, colIndex);
57982 this.fireEvent("selectionchange", this, this.selection);
57987 isSelectable : function(rowIndex, colIndex, cm){
57988 return !cm.isHidden(colIndex);
57992 handleKeyDown : function(e){
57993 //Roo.log('Cell Sel Model handleKeyDown');
57994 if(!e.isNavKeyPress()){
57997 var g = this.grid, s = this.selection;
58000 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58002 this.select(cell[0], cell[1]);
58007 var walk = function(row, col, step){
58008 return g.walkCells(row, col, step, sm.isSelectable, sm);
58010 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58017 // handled by onEditorKey
58018 if (g.isEditor && g.editing) {
58022 newCell = walk(r, c-1, -1);
58024 newCell = walk(r, c+1, 1);
58029 newCell = walk(r+1, c, 1);
58033 newCell = walk(r-1, c, -1);
58037 newCell = walk(r, c+1, 1);
58041 newCell = walk(r, c-1, -1);
58046 if(g.isEditor && !g.editing){
58047 g.startEditing(r, c);
58056 this.select(newCell[0], newCell[1]);
58062 acceptsNav : function(row, col, cm){
58063 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58067 * @param {Number} field (not used) - as it's normally used as a listener
58068 * @param {Number} e - event - fake it by using
58070 * var e = Roo.EventObjectImpl.prototype;
58071 * e.keyCode = e.TAB
58075 onEditorKey : function(field, e){
58077 var k = e.getKey(),
58080 ed = g.activeEditor,
58082 ///Roo.log('onEditorKey' + k);
58085 if (this.enter_is_tab && k == e.ENTER) {
58091 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58093 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58099 } else if(k == e.ENTER && !e.ctrlKey){
58102 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58104 } else if(k == e.ESC){
58109 var ecall = { cell : newCell, forward : forward };
58110 this.fireEvent('beforeeditnext', ecall );
58111 newCell = ecall.cell;
58112 forward = ecall.forward;
58116 //Roo.log('next cell after edit');
58117 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58118 } else if (forward) {
58119 // tabbed past last
58120 this.fireEvent.defer(100, this, ['tabend',this]);
58125 * Ext JS Library 1.1.1
58126 * Copyright(c) 2006-2007, Ext JS, LLC.
58128 * Originally Released Under LGPL - original licence link has changed is not relivant.
58131 * <script type="text/javascript">
58135 * @class Roo.grid.EditorGrid
58136 * @extends Roo.grid.Grid
58137 * Class for creating and editable grid.
58138 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58139 * The container MUST have some type of size defined for the grid to fill. The container will be
58140 * automatically set to position relative if it isn't already.
58141 * @param {Object} dataSource The data model to bind to
58142 * @param {Object} colModel The column model with info about this grid's columns
58144 Roo.grid.EditorGrid = function(container, config){
58145 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58146 this.getGridEl().addClass("xedit-grid");
58148 if(!this.selModel){
58149 this.selModel = new Roo.grid.CellSelectionModel();
58152 this.activeEditor = null;
58156 * @event beforeedit
58157 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58158 * <ul style="padding:5px;padding-left:16px;">
58159 * <li>grid - This grid</li>
58160 * <li>record - The record being edited</li>
58161 * <li>field - The field name being edited</li>
58162 * <li>value - The value for the field being edited.</li>
58163 * <li>row - The grid row index</li>
58164 * <li>column - The grid column index</li>
58165 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58167 * @param {Object} e An edit event (see above for description)
58169 "beforeedit" : true,
58172 * Fires after a cell is edited. <br />
58173 * <ul style="padding:5px;padding-left:16px;">
58174 * <li>grid - This grid</li>
58175 * <li>record - The record being edited</li>
58176 * <li>field - The field name being edited</li>
58177 * <li>value - The value being set</li>
58178 * <li>originalValue - The original value for the field, before the edit.</li>
58179 * <li>row - The grid row index</li>
58180 * <li>column - The grid column index</li>
58182 * @param {Object} e An edit event (see above for description)
58184 "afteredit" : true,
58186 * @event validateedit
58187 * Fires after a cell is edited, but before the value is set in the record.
58188 * You can use this to modify the value being set in the field, Return false
58189 * to cancel the change. The edit event object has the following properties <br />
58190 * <ul style="padding:5px;padding-left:16px;">
58191 * <li>editor - This editor</li>
58192 * <li>grid - This grid</li>
58193 * <li>record - The record being edited</li>
58194 * <li>field - The field name being edited</li>
58195 * <li>value - The value being set</li>
58196 * <li>originalValue - The original value for the field, before the edit.</li>
58197 * <li>row - The grid row index</li>
58198 * <li>column - The grid column index</li>
58199 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58201 * @param {Object} e An edit event (see above for description)
58203 "validateedit" : true
58205 this.on("bodyscroll", this.stopEditing, this);
58206 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58209 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58211 * @cfg {Number} clicksToEdit
58212 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58219 trackMouseOver: false, // causes very odd FF errors
58221 onCellDblClick : function(g, row, col){
58222 this.startEditing(row, col);
58225 onEditComplete : function(ed, value, startValue){
58226 this.editing = false;
58227 this.activeEditor = null;
58228 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58230 var field = this.colModel.getDataIndex(ed.col);
58235 originalValue: startValue,
58242 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58245 if(String(value) !== String(startValue)){
58247 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58248 r.set(field, e.value);
58249 // if we are dealing with a combo box..
58250 // then we also set the 'name' colum to be the displayField
58251 if (ed.field.displayField && ed.field.name) {
58252 r.set(ed.field.name, ed.field.el.dom.value);
58255 delete e.cancel; //?? why!!!
58256 this.fireEvent("afteredit", e);
58259 this.fireEvent("afteredit", e); // always fire it!
58261 this.view.focusCell(ed.row, ed.col);
58265 * Starts editing the specified for the specified row/column
58266 * @param {Number} rowIndex
58267 * @param {Number} colIndex
58269 startEditing : function(row, col){
58270 this.stopEditing();
58271 if(this.colModel.isCellEditable(col, row)){
58272 this.view.ensureVisible(row, col, true);
58274 var r = this.dataSource.getAt(row);
58275 var field = this.colModel.getDataIndex(col);
58276 var cell = Roo.get(this.view.getCell(row,col));
58281 value: r.data[field],
58286 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58287 this.editing = true;
58288 var ed = this.colModel.getCellEditor(col, row);
58294 ed.render(ed.parentEl || document.body);
58300 (function(){ // complex but required for focus issues in safari, ie and opera
58304 ed.on("complete", this.onEditComplete, this, {single: true});
58305 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58306 this.activeEditor = ed;
58307 var v = r.data[field];
58308 ed.startEdit(this.view.getCell(row, col), v);
58309 // combo's with 'displayField and name set
58310 if (ed.field.displayField && ed.field.name) {
58311 ed.field.el.dom.value = r.data[ed.field.name];
58315 }).defer(50, this);
58321 * Stops any active editing
58323 stopEditing : function(){
58324 if(this.activeEditor){
58325 this.activeEditor.completeEdit();
58327 this.activeEditor = null;
58331 * Called to get grid's drag proxy text, by default returns this.ddText.
58334 getDragDropText : function(){
58335 var count = this.selModel.getSelectedCell() ? 1 : 0;
58336 return String.format(this.ddText, count, count == 1 ? '' : 's');
58341 * Ext JS Library 1.1.1
58342 * Copyright(c) 2006-2007, Ext JS, LLC.
58344 * Originally Released Under LGPL - original licence link has changed is not relivant.
58347 * <script type="text/javascript">
58350 // private - not really -- you end up using it !
58351 // This is a support class used internally by the Grid components
58354 * @class Roo.grid.GridEditor
58355 * @extends Roo.Editor
58356 * Class for creating and editable grid elements.
58357 * @param {Object} config any settings (must include field)
58359 Roo.grid.GridEditor = function(field, config){
58360 if (!config && field.field) {
58362 field = Roo.factory(config.field, Roo.form);
58364 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58365 field.monitorTab = false;
58368 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58371 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58374 alignment: "tl-tl",
58377 cls: "x-small-editor x-grid-editor",
58382 * Ext JS Library 1.1.1
58383 * Copyright(c) 2006-2007, Ext JS, LLC.
58385 * Originally Released Under LGPL - original licence link has changed is not relivant.
58388 * <script type="text/javascript">
58393 Roo.grid.PropertyRecord = Roo.data.Record.create([
58394 {name:'name',type:'string'}, 'value'
58398 Roo.grid.PropertyStore = function(grid, source){
58400 this.store = new Roo.data.Store({
58401 recordType : Roo.grid.PropertyRecord
58403 this.store.on('update', this.onUpdate, this);
58405 this.setSource(source);
58407 Roo.grid.PropertyStore.superclass.constructor.call(this);
58412 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58413 setSource : function(o){
58415 this.store.removeAll();
58418 if(this.isEditableValue(o[k])){
58419 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58422 this.store.loadRecords({records: data}, {}, true);
58425 onUpdate : function(ds, record, type){
58426 if(type == Roo.data.Record.EDIT){
58427 var v = record.data['value'];
58428 var oldValue = record.modified['value'];
58429 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58430 this.source[record.id] = v;
58432 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58439 getProperty : function(row){
58440 return this.store.getAt(row);
58443 isEditableValue: function(val){
58444 if(val && val instanceof Date){
58446 }else if(typeof val == 'object' || typeof val == 'function'){
58452 setValue : function(prop, value){
58453 this.source[prop] = value;
58454 this.store.getById(prop).set('value', value);
58457 getSource : function(){
58458 return this.source;
58462 Roo.grid.PropertyColumnModel = function(grid, store){
58465 g.PropertyColumnModel.superclass.constructor.call(this, [
58466 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58467 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58469 this.store = store;
58470 this.bselect = Roo.DomHelper.append(document.body, {
58471 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58472 {tag: 'option', value: 'true', html: 'true'},
58473 {tag: 'option', value: 'false', html: 'false'}
58476 Roo.id(this.bselect);
58479 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58480 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58481 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58482 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58483 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58485 this.renderCellDelegate = this.renderCell.createDelegate(this);
58486 this.renderPropDelegate = this.renderProp.createDelegate(this);
58489 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58493 valueText : 'Value',
58495 dateFormat : 'm/j/Y',
58498 renderDate : function(dateVal){
58499 return dateVal.dateFormat(this.dateFormat);
58502 renderBool : function(bVal){
58503 return bVal ? 'true' : 'false';
58506 isCellEditable : function(colIndex, rowIndex){
58507 return colIndex == 1;
58510 getRenderer : function(col){
58512 this.renderCellDelegate : this.renderPropDelegate;
58515 renderProp : function(v){
58516 return this.getPropertyName(v);
58519 renderCell : function(val){
58521 if(val instanceof Date){
58522 rv = this.renderDate(val);
58523 }else if(typeof val == 'boolean'){
58524 rv = this.renderBool(val);
58526 return Roo.util.Format.htmlEncode(rv);
58529 getPropertyName : function(name){
58530 var pn = this.grid.propertyNames;
58531 return pn && pn[name] ? pn[name] : name;
58534 getCellEditor : function(colIndex, rowIndex){
58535 var p = this.store.getProperty(rowIndex);
58536 var n = p.data['name'], val = p.data['value'];
58538 if(typeof(this.grid.customEditors[n]) == 'string'){
58539 return this.editors[this.grid.customEditors[n]];
58541 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58542 return this.grid.customEditors[n];
58544 if(val instanceof Date){
58545 return this.editors['date'];
58546 }else if(typeof val == 'number'){
58547 return this.editors['number'];
58548 }else if(typeof val == 'boolean'){
58549 return this.editors['boolean'];
58551 return this.editors['string'];
58557 * @class Roo.grid.PropertyGrid
58558 * @extends Roo.grid.EditorGrid
58559 * This class represents the interface of a component based property grid control.
58560 * <br><br>Usage:<pre><code>
58561 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58569 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58570 * The container MUST have some type of size defined for the grid to fill. The container will be
58571 * automatically set to position relative if it isn't already.
58572 * @param {Object} config A config object that sets properties on this grid.
58574 Roo.grid.PropertyGrid = function(container, config){
58575 config = config || {};
58576 var store = new Roo.grid.PropertyStore(this);
58577 this.store = store;
58578 var cm = new Roo.grid.PropertyColumnModel(this, store);
58579 store.store.sort('name', 'ASC');
58580 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58583 enableColLock:false,
58584 enableColumnMove:false,
58586 trackMouseOver: false,
58589 this.getGridEl().addClass('x-props-grid');
58590 this.lastEditRow = null;
58591 this.on('columnresize', this.onColumnResize, this);
58594 * @event beforepropertychange
58595 * Fires before a property changes (return false to stop?)
58596 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58597 * @param {String} id Record Id
58598 * @param {String} newval New Value
58599 * @param {String} oldval Old Value
58601 "beforepropertychange": true,
58603 * @event propertychange
58604 * Fires after a property changes
58605 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58606 * @param {String} id Record Id
58607 * @param {String} newval New Value
58608 * @param {String} oldval Old Value
58610 "propertychange": true
58612 this.customEditors = this.customEditors || {};
58614 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58617 * @cfg {Object} customEditors map of colnames=> custom editors.
58618 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58619 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58620 * false disables editing of the field.
58624 * @cfg {Object} propertyNames map of property Names to their displayed value
58627 render : function(){
58628 Roo.grid.PropertyGrid.superclass.render.call(this);
58629 this.autoSize.defer(100, this);
58632 autoSize : function(){
58633 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58635 this.view.fitColumns();
58639 onColumnResize : function(){
58640 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58644 * Sets the data for the Grid
58645 * accepts a Key => Value object of all the elements avaiable.
58646 * @param {Object} data to appear in grid.
58648 setSource : function(source){
58649 this.store.setSource(source);
58653 * Gets all the data from the grid.
58654 * @return {Object} data data stored in grid
58656 getSource : function(){
58657 return this.store.getSource();
58666 * @class Roo.grid.Calendar
58667 * @extends Roo.util.Grid
58668 * This class extends the Grid to provide a calendar widget
58669 * <br><br>Usage:<pre><code>
58670 var grid = new Roo.grid.Calendar("my-container-id", {
58673 selModel: mySelectionModel,
58674 autoSizeColumns: true,
58675 monitorWindowResize: false,
58676 trackMouseOver: true
58677 eventstore : real data store..
58683 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58684 * The container MUST have some type of size defined for the grid to fill. The container will be
58685 * automatically set to position relative if it isn't already.
58686 * @param {Object} config A config object that sets properties on this grid.
58688 Roo.grid.Calendar = function(container, config){
58689 // initialize the container
58690 this.container = Roo.get(container);
58691 this.container.update("");
58692 this.container.setStyle("overflow", "hidden");
58693 this.container.addClass('x-grid-container');
58695 this.id = this.container.id;
58697 Roo.apply(this, config);
58698 // check and correct shorthanded configs
58702 for (var r = 0;r < 6;r++) {
58705 for (var c =0;c < 7;c++) {
58709 if (this.eventStore) {
58710 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58711 this.eventStore.on('load',this.onLoad, this);
58712 this.eventStore.on('beforeload',this.clearEvents, this);
58716 this.dataSource = new Roo.data.Store({
58717 proxy: new Roo.data.MemoryProxy(rows),
58718 reader: new Roo.data.ArrayReader({}, [
58719 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58722 this.dataSource.load();
58723 this.ds = this.dataSource;
58724 this.ds.xmodule = this.xmodule || false;
58727 var cellRender = function(v,x,r)
58729 return String.format(
58730 '<div class="fc-day fc-widget-content"><div>' +
58731 '<div class="fc-event-container"></div>' +
58732 '<div class="fc-day-number">{0}</div>'+
58734 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58735 '</div></div>', v);
58740 this.colModel = new Roo.grid.ColumnModel( [
58742 xtype: 'ColumnModel',
58744 dataIndex : 'weekday0',
58746 renderer : cellRender
58749 xtype: 'ColumnModel',
58751 dataIndex : 'weekday1',
58753 renderer : cellRender
58756 xtype: 'ColumnModel',
58758 dataIndex : 'weekday2',
58759 header : 'Tuesday',
58760 renderer : cellRender
58763 xtype: 'ColumnModel',
58765 dataIndex : 'weekday3',
58766 header : 'Wednesday',
58767 renderer : cellRender
58770 xtype: 'ColumnModel',
58772 dataIndex : 'weekday4',
58773 header : 'Thursday',
58774 renderer : cellRender
58777 xtype: 'ColumnModel',
58779 dataIndex : 'weekday5',
58781 renderer : cellRender
58784 xtype: 'ColumnModel',
58786 dataIndex : 'weekday6',
58787 header : 'Saturday',
58788 renderer : cellRender
58791 this.cm = this.colModel;
58792 this.cm.xmodule = this.xmodule || false;
58796 //this.selModel = new Roo.grid.CellSelectionModel();
58797 //this.sm = this.selModel;
58798 //this.selModel.init(this);
58802 this.container.setWidth(this.width);
58806 this.container.setHeight(this.height);
58813 * The raw click event for the entire grid.
58814 * @param {Roo.EventObject} e
58819 * The raw dblclick event for the entire grid.
58820 * @param {Roo.EventObject} e
58824 * @event contextmenu
58825 * The raw contextmenu event for the entire grid.
58826 * @param {Roo.EventObject} e
58828 "contextmenu" : true,
58831 * The raw mousedown event for the entire grid.
58832 * @param {Roo.EventObject} e
58834 "mousedown" : true,
58837 * The raw mouseup event for the entire grid.
58838 * @param {Roo.EventObject} e
58843 * The raw mouseover event for the entire grid.
58844 * @param {Roo.EventObject} e
58846 "mouseover" : true,
58849 * The raw mouseout event for the entire grid.
58850 * @param {Roo.EventObject} e
58855 * The raw keypress event for the entire grid.
58856 * @param {Roo.EventObject} e
58861 * The raw keydown event for the entire grid.
58862 * @param {Roo.EventObject} e
58870 * Fires when a cell is clicked
58871 * @param {Grid} this
58872 * @param {Number} rowIndex
58873 * @param {Number} columnIndex
58874 * @param {Roo.EventObject} e
58876 "cellclick" : true,
58878 * @event celldblclick
58879 * Fires when a cell is double clicked
58880 * @param {Grid} this
58881 * @param {Number} rowIndex
58882 * @param {Number} columnIndex
58883 * @param {Roo.EventObject} e
58885 "celldblclick" : true,
58888 * Fires when a row is clicked
58889 * @param {Grid} this
58890 * @param {Number} rowIndex
58891 * @param {Roo.EventObject} e
58895 * @event rowdblclick
58896 * Fires when a row is double clicked
58897 * @param {Grid} this
58898 * @param {Number} rowIndex
58899 * @param {Roo.EventObject} e
58901 "rowdblclick" : true,
58903 * @event headerclick
58904 * Fires when a header is clicked
58905 * @param {Grid} this
58906 * @param {Number} columnIndex
58907 * @param {Roo.EventObject} e
58909 "headerclick" : true,
58911 * @event headerdblclick
58912 * Fires when a header cell is double clicked
58913 * @param {Grid} this
58914 * @param {Number} columnIndex
58915 * @param {Roo.EventObject} e
58917 "headerdblclick" : true,
58919 * @event rowcontextmenu
58920 * Fires when a row is right clicked
58921 * @param {Grid} this
58922 * @param {Number} rowIndex
58923 * @param {Roo.EventObject} e
58925 "rowcontextmenu" : true,
58927 * @event cellcontextmenu
58928 * Fires when a cell is right clicked
58929 * @param {Grid} this
58930 * @param {Number} rowIndex
58931 * @param {Number} cellIndex
58932 * @param {Roo.EventObject} e
58934 "cellcontextmenu" : true,
58936 * @event headercontextmenu
58937 * Fires when a header is right clicked
58938 * @param {Grid} this
58939 * @param {Number} columnIndex
58940 * @param {Roo.EventObject} e
58942 "headercontextmenu" : true,
58944 * @event bodyscroll
58945 * Fires when the body element is scrolled
58946 * @param {Number} scrollLeft
58947 * @param {Number} scrollTop
58949 "bodyscroll" : true,
58951 * @event columnresize
58952 * Fires when the user resizes a column
58953 * @param {Number} columnIndex
58954 * @param {Number} newSize
58956 "columnresize" : true,
58958 * @event columnmove
58959 * Fires when the user moves a column
58960 * @param {Number} oldIndex
58961 * @param {Number} newIndex
58963 "columnmove" : true,
58966 * Fires when row(s) start being dragged
58967 * @param {Grid} this
58968 * @param {Roo.GridDD} dd The drag drop object
58969 * @param {event} e The raw browser event
58971 "startdrag" : true,
58974 * Fires when a drag operation is complete
58975 * @param {Grid} this
58976 * @param {Roo.GridDD} dd The drag drop object
58977 * @param {event} e The raw browser event
58982 * Fires when dragged row(s) are dropped on a valid DD target
58983 * @param {Grid} this
58984 * @param {Roo.GridDD} dd The drag drop object
58985 * @param {String} targetId The target drag drop object
58986 * @param {event} e The raw browser event
58991 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
58992 * @param {Grid} this
58993 * @param {Roo.GridDD} dd The drag drop object
58994 * @param {String} targetId The target drag drop object
58995 * @param {event} e The raw browser event
59000 * Fires when the dragged row(s) first cross another DD target while being dragged
59001 * @param {Grid} this
59002 * @param {Roo.GridDD} dd The drag drop object
59003 * @param {String} targetId The target drag drop object
59004 * @param {event} e The raw browser event
59006 "dragenter" : true,
59009 * Fires when the dragged row(s) leave another DD target while being dragged
59010 * @param {Grid} this
59011 * @param {Roo.GridDD} dd The drag drop object
59012 * @param {String} targetId The target drag drop object
59013 * @param {event} e The raw browser event
59018 * Fires when a row is rendered, so you can change add a style to it.
59019 * @param {GridView} gridview The grid view
59020 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59026 * Fires when the grid is rendered
59027 * @param {Grid} grid
59032 * Fires when a date is selected
59033 * @param {DatePicker} this
59034 * @param {Date} date The selected date
59038 * @event monthchange
59039 * Fires when the displayed month changes
59040 * @param {DatePicker} this
59041 * @param {Date} date The selected month
59043 'monthchange': true,
59045 * @event evententer
59046 * Fires when mouse over an event
59047 * @param {Calendar} this
59048 * @param {event} Event
59050 'evententer': true,
59052 * @event eventleave
59053 * Fires when the mouse leaves an
59054 * @param {Calendar} this
59057 'eventleave': true,
59059 * @event eventclick
59060 * Fires when the mouse click an
59061 * @param {Calendar} this
59064 'eventclick': true,
59066 * @event eventrender
59067 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59068 * @param {Calendar} this
59069 * @param {data} data to be modified
59071 'eventrender': true
59075 Roo.grid.Grid.superclass.constructor.call(this);
59076 this.on('render', function() {
59077 this.view.el.addClass('x-grid-cal');
59079 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59083 if (!Roo.grid.Calendar.style) {
59084 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59087 '.x-grid-cal .x-grid-col' : {
59088 height: 'auto !important',
59089 'vertical-align': 'top'
59091 '.x-grid-cal .fc-event-hori' : {
59102 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59104 * @cfg {Store} eventStore The store that loads events.
59109 activeDate : false,
59112 monitorWindowResize : false,
59115 resizeColumns : function() {
59116 var col = (this.view.el.getWidth() / 7) - 3;
59117 // loop through cols, and setWidth
59118 for(var i =0 ; i < 7 ; i++){
59119 this.cm.setColumnWidth(i, col);
59122 setDate :function(date) {
59124 Roo.log('setDate?');
59126 this.resizeColumns();
59127 var vd = this.activeDate;
59128 this.activeDate = date;
59129 // if(vd && this.el){
59130 // var t = date.getTime();
59131 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59132 // Roo.log('using add remove');
59134 // this.fireEvent('monthchange', this, date);
59136 // this.cells.removeClass("fc-state-highlight");
59137 // this.cells.each(function(c){
59138 // if(c.dateValue == t){
59139 // c.addClass("fc-state-highlight");
59140 // setTimeout(function(){
59141 // try{c.dom.firstChild.focus();}catch(e){}
59151 var days = date.getDaysInMonth();
59153 var firstOfMonth = date.getFirstDateOfMonth();
59154 var startingPos = firstOfMonth.getDay()-this.startDay;
59156 if(startingPos < this.startDay){
59160 var pm = date.add(Date.MONTH, -1);
59161 var prevStart = pm.getDaysInMonth()-startingPos;
59165 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59167 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59168 //this.cells.addClassOnOver('fc-state-hover');
59170 var cells = this.cells.elements;
59171 var textEls = this.textNodes;
59173 //Roo.each(cells, function(cell){
59174 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59177 days += startingPos;
59179 // convert everything to numbers so it's fast
59180 var day = 86400000;
59181 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59184 //Roo.log(prevStart);
59186 var today = new Date().clearTime().getTime();
59187 var sel = date.clearTime().getTime();
59188 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59189 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59190 var ddMatch = this.disabledDatesRE;
59191 var ddText = this.disabledDatesText;
59192 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59193 var ddaysText = this.disabledDaysText;
59194 var format = this.format;
59196 var setCellClass = function(cal, cell){
59198 //Roo.log('set Cell Class');
59200 var t = d.getTime();
59205 cell.dateValue = t;
59207 cell.className += " fc-today";
59208 cell.className += " fc-state-highlight";
59209 cell.title = cal.todayText;
59212 // disable highlight in other month..
59213 cell.className += " fc-state-highlight";
59218 //cell.className = " fc-state-disabled";
59219 cell.title = cal.minText;
59223 //cell.className = " fc-state-disabled";
59224 cell.title = cal.maxText;
59228 if(ddays.indexOf(d.getDay()) != -1){
59229 // cell.title = ddaysText;
59230 // cell.className = " fc-state-disabled";
59233 if(ddMatch && format){
59234 var fvalue = d.dateFormat(format);
59235 if(ddMatch.test(fvalue)){
59236 cell.title = ddText.replace("%0", fvalue);
59237 cell.className = " fc-state-disabled";
59241 if (!cell.initialClassName) {
59242 cell.initialClassName = cell.dom.className;
59245 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59250 for(; i < startingPos; i++) {
59251 cells[i].dayName = (++prevStart);
59252 Roo.log(textEls[i]);
59253 d.setDate(d.getDate()+1);
59255 //cells[i].className = "fc-past fc-other-month";
59256 setCellClass(this, cells[i]);
59261 for(; i < days; i++){
59262 intDay = i - startingPos + 1;
59263 cells[i].dayName = (intDay);
59264 d.setDate(d.getDate()+1);
59266 cells[i].className = ''; // "x-date-active";
59267 setCellClass(this, cells[i]);
59271 for(; i < 42; i++) {
59272 //textEls[i].innerHTML = (++extraDays);
59274 d.setDate(d.getDate()+1);
59275 cells[i].dayName = (++extraDays);
59276 cells[i].className = "fc-future fc-other-month";
59277 setCellClass(this, cells[i]);
59280 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59282 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59284 // this will cause all the cells to mis
59287 for (var r = 0;r < 6;r++) {
59288 for (var c =0;c < 7;c++) {
59289 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59293 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59294 for(i=0;i<cells.length;i++) {
59296 this.cells.elements[i].dayName = cells[i].dayName ;
59297 this.cells.elements[i].className = cells[i].className;
59298 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59299 this.cells.elements[i].title = cells[i].title ;
59300 this.cells.elements[i].dateValue = cells[i].dateValue ;
59306 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59307 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59309 ////if(totalRows != 6){
59310 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59311 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59314 this.fireEvent('monthchange', this, date);
59319 * Returns the grid's SelectionModel.
59320 * @return {SelectionModel}
59322 getSelectionModel : function(){
59323 if(!this.selModel){
59324 this.selModel = new Roo.grid.CellSelectionModel();
59326 return this.selModel;
59330 this.eventStore.load()
59336 findCell : function(dt) {
59337 dt = dt.clearTime().getTime();
59339 this.cells.each(function(c){
59340 //Roo.log("check " +c.dateValue + '?=' + dt);
59341 if(c.dateValue == dt){
59351 findCells : function(rec) {
59352 var s = rec.data.start_dt.clone().clearTime().getTime();
59354 var e= rec.data.end_dt.clone().clearTime().getTime();
59357 this.cells.each(function(c){
59358 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59360 if(c.dateValue > e){
59363 if(c.dateValue < s){
59372 findBestRow: function(cells)
59376 for (var i =0 ; i < cells.length;i++) {
59377 ret = Math.max(cells[i].rows || 0,ret);
59384 addItem : function(rec)
59386 // look for vertical location slot in
59387 var cells = this.findCells(rec);
59389 rec.row = this.findBestRow(cells);
59391 // work out the location.
59395 for(var i =0; i < cells.length; i++) {
59403 if (crow.start.getY() == cells[i].getY()) {
59405 crow.end = cells[i];
59421 for (var i = 0; i < cells.length;i++) {
59422 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59429 clearEvents: function() {
59431 if (!this.eventStore.getCount()) {
59434 // reset number of rows in cells.
59435 Roo.each(this.cells.elements, function(c){
59439 this.eventStore.each(function(e) {
59440 this.clearEvent(e);
59445 clearEvent : function(ev)
59448 Roo.each(ev.els, function(el) {
59449 el.un('mouseenter' ,this.onEventEnter, this);
59450 el.un('mouseleave' ,this.onEventLeave, this);
59458 renderEvent : function(ev,ctr) {
59460 ctr = this.view.el.select('.fc-event-container',true).first();
59464 this.clearEvent(ev);
59470 var cells = ev.cells;
59471 var rows = ev.rows;
59472 this.fireEvent('eventrender', this, ev);
59474 for(var i =0; i < rows.length; i++) {
59478 cls += ' fc-event-start';
59480 if ((i+1) == rows.length) {
59481 cls += ' fc-event-end';
59484 //Roo.log(ev.data);
59485 // how many rows should it span..
59486 var cg = this.eventTmpl.append(ctr,Roo.apply({
59489 }, ev.data) , true);
59492 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59493 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59494 cg.on('click', this.onEventClick, this, ev);
59498 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59499 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59502 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59503 cg.setWidth(ebox.right - sbox.x -2);
59507 renderEvents: function()
59509 // first make sure there is enough space..
59511 if (!this.eventTmpl) {
59512 this.eventTmpl = new Roo.Template(
59513 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59514 '<div class="fc-event-inner">' +
59515 '<span class="fc-event-time">{time}</span>' +
59516 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59518 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59526 this.cells.each(function(c) {
59527 //Roo.log(c.select('.fc-day-content div',true).first());
59528 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59531 var ctr = this.view.el.select('.fc-event-container',true).first();
59534 this.eventStore.each(function(ev){
59536 this.renderEvent(ev);
59540 this.view.layout();
59544 onEventEnter: function (e, el,event,d) {
59545 this.fireEvent('evententer', this, el, event);
59548 onEventLeave: function (e, el,event,d) {
59549 this.fireEvent('eventleave', this, el, event);
59552 onEventClick: function (e, el,event,d) {
59553 this.fireEvent('eventclick', this, el, event);
59556 onMonthChange: function () {
59560 onLoad: function () {
59562 //Roo.log('calendar onload');
59564 if(this.eventStore.getCount() > 0){
59568 this.eventStore.each(function(d){
59573 if (typeof(add.end_dt) == 'undefined') {
59574 Roo.log("Missing End time in calendar data: ");
59578 if (typeof(add.start_dt) == 'undefined') {
59579 Roo.log("Missing Start time in calendar data: ");
59583 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59584 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59585 add.id = add.id || d.id;
59586 add.title = add.title || '??';
59594 this.renderEvents();
59604 render : function ()
59608 if (!this.view.el.hasClass('course-timesheet')) {
59609 this.view.el.addClass('course-timesheet');
59611 if (this.tsStyle) {
59616 Roo.log(_this.grid.view.el.getWidth());
59619 this.tsStyle = Roo.util.CSS.createStyleSheet({
59620 '.course-timesheet .x-grid-row' : {
59623 '.x-grid-row td' : {
59624 'vertical-align' : 0
59626 '.course-edit-link' : {
59628 'text-overflow' : 'ellipsis',
59629 'overflow' : 'hidden',
59630 'white-space' : 'nowrap',
59631 'cursor' : 'pointer'
59636 '.de-act-sup-link' : {
59637 'color' : 'purple',
59638 'text-decoration' : 'line-through'
59642 'text-decoration' : 'line-through'
59644 '.course-timesheet .course-highlight' : {
59645 'border-top-style': 'dashed !important',
59646 'border-bottom-bottom': 'dashed !important'
59648 '.course-timesheet .course-item' : {
59649 'font-family' : 'tahoma, arial, helvetica',
59650 'font-size' : '11px',
59651 'overflow' : 'hidden',
59652 'padding-left' : '10px',
59653 'padding-right' : '10px',
59654 'padding-top' : '10px'
59662 monitorWindowResize : false,
59663 cellrenderer : function(v,x,r)
59668 xtype: 'CellSelectionModel',
59675 beforeload : function (_self, options)
59677 options.params = options.params || {};
59678 options.params._month = _this.monthField.getValue();
59679 options.params.limit = 9999;
59680 options.params['sort'] = 'when_dt';
59681 options.params['dir'] = 'ASC';
59682 this.proxy.loadResponse = this.loadResponse;
59684 //this.addColumns();
59686 load : function (_self, records, options)
59688 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59689 // if you click on the translation.. you can edit it...
59690 var el = Roo.get(this);
59691 var id = el.dom.getAttribute('data-id');
59692 var d = el.dom.getAttribute('data-date');
59693 var t = el.dom.getAttribute('data-time');
59694 //var id = this.child('span').dom.textContent;
59697 Pman.Dialog.CourseCalendar.show({
59701 productitem_active : id ? 1 : 0
59703 _this.grid.ds.load({});
59708 _this.panel.fireEvent('resize', [ '', '' ]);
59711 loadResponse : function(o, success, response){
59712 // this is overridden on before load..
59714 Roo.log("our code?");
59715 //Roo.log(success);
59716 //Roo.log(response)
59717 delete this.activeRequest;
59719 this.fireEvent("loadexception", this, o, response);
59720 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59725 result = o.reader.read(response);
59727 Roo.log("load exception?");
59728 this.fireEvent("loadexception", this, o, response, e);
59729 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59732 Roo.log("ready...");
59733 // loop through result.records;
59734 // and set this.tdate[date] = [] << array of records..
59736 Roo.each(result.records, function(r){
59738 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59739 _this.tdata[r.data.when_dt.format('j')] = [];
59741 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59744 //Roo.log(_this.tdata);
59746 result.records = [];
59747 result.totalRecords = 6;
59749 // let's generate some duumy records for the rows.
59750 //var st = _this.dateField.getValue();
59752 // work out monday..
59753 //st = st.add(Date.DAY, -1 * st.format('w'));
59755 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59757 var firstOfMonth = date.getFirstDayOfMonth();
59758 var days = date.getDaysInMonth();
59760 var firstAdded = false;
59761 for (var i = 0; i < result.totalRecords ; i++) {
59762 //var d= st.add(Date.DAY, i);
59765 for(var w = 0 ; w < 7 ; w++){
59766 if(!firstAdded && firstOfMonth != w){
59773 var dd = (d > 0 && d < 10) ? "0"+d : d;
59774 row['weekday'+w] = String.format(
59775 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59776 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59778 date.format('Y-m-')+dd
59781 if(typeof(_this.tdata[d]) != 'undefined'){
59782 Roo.each(_this.tdata[d], function(r){
59786 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59787 if(r.parent_id*1>0){
59788 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59791 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59792 deactive = 'de-act-link';
59795 row['weekday'+w] += String.format(
59796 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59798 r.product_id_name, //1
59799 r.when_dt.format('h:ia'), //2
59809 // only do this if something added..
59811 result.records.push(_this.grid.dataSource.reader.newRow(row));
59815 // push it twice. (second one with an hour..
59819 this.fireEvent("load", this, o, o.request.arg);
59820 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59822 sortInfo : {field: 'when_dt', direction : 'ASC' },
59824 xtype: 'HttpProxy',
59827 url : baseURL + '/Roo/Shop_course.php'
59830 xtype: 'JsonReader',
59847 'name': 'parent_id',
59851 'name': 'product_id',
59855 'name': 'productitem_id',
59873 click : function (_self, e)
59875 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59876 sd.setMonth(sd.getMonth()-1);
59877 _this.monthField.setValue(sd.format('Y-m-d'));
59878 _this.grid.ds.load({});
59884 xtype: 'Separator',
59888 xtype: 'MonthField',
59891 render : function (_self)
59893 _this.monthField = _self;
59894 // _this.monthField.set today
59896 select : function (combo, date)
59898 _this.grid.ds.load({});
59901 value : (function() { return new Date(); })()
59904 xtype: 'Separator',
59910 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
59920 click : function (_self, e)
59922 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59923 sd.setMonth(sd.getMonth()+1);
59924 _this.monthField.setValue(sd.format('Y-m-d'));
59925 _this.grid.ds.load({});
59938 * Ext JS Library 1.1.1
59939 * Copyright(c) 2006-2007, Ext JS, LLC.
59941 * Originally Released Under LGPL - original licence link has changed is not relivant.
59944 * <script type="text/javascript">
59948 * @class Roo.LoadMask
59949 * A simple utility class for generically masking elements while loading data. If the element being masked has
59950 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
59951 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
59952 * element's UpdateManager load indicator and will be destroyed after the initial load.
59954 * Create a new LoadMask
59955 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
59956 * @param {Object} config The config object
59958 Roo.LoadMask = function(el, config){
59959 this.el = Roo.get(el);
59960 Roo.apply(this, config);
59962 this.store.on('beforeload', this.onBeforeLoad, this);
59963 this.store.on('load', this.onLoad, this);
59964 this.store.on('loadexception', this.onLoadException, this);
59965 this.removeMask = false;
59967 var um = this.el.getUpdateManager();
59968 um.showLoadIndicator = false; // disable the default indicator
59969 um.on('beforeupdate', this.onBeforeLoad, this);
59970 um.on('update', this.onLoad, this);
59971 um.on('failure', this.onLoad, this);
59972 this.removeMask = true;
59976 Roo.LoadMask.prototype = {
59978 * @cfg {Boolean} removeMask
59979 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
59980 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
59983 * @cfg {String} msg
59984 * The text to display in a centered loading message box (defaults to 'Loading...')
59986 msg : 'Loading...',
59988 * @cfg {String} msgCls
59989 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
59991 msgCls : 'x-mask-loading',
59994 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60000 * Disables the mask to prevent it from being displayed
60002 disable : function(){
60003 this.disabled = true;
60007 * Enables the mask so that it can be displayed
60009 enable : function(){
60010 this.disabled = false;
60013 onLoadException : function()
60015 Roo.log(arguments);
60017 if (typeof(arguments[3]) != 'undefined') {
60018 Roo.MessageBox.alert("Error loading",arguments[3]);
60022 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60023 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60032 this.el.unmask(this.removeMask);
60035 onLoad : function()
60037 this.el.unmask(this.removeMask);
60041 onBeforeLoad : function(){
60042 if(!this.disabled){
60043 this.el.mask(this.msg, this.msgCls);
60048 destroy : function(){
60050 this.store.un('beforeload', this.onBeforeLoad, this);
60051 this.store.un('load', this.onLoad, this);
60052 this.store.un('loadexception', this.onLoadException, this);
60054 var um = this.el.getUpdateManager();
60055 um.un('beforeupdate', this.onBeforeLoad, this);
60056 um.un('update', this.onLoad, this);
60057 um.un('failure', this.onLoad, this);
60062 * Ext JS Library 1.1.1
60063 * Copyright(c) 2006-2007, Ext JS, LLC.
60065 * Originally Released Under LGPL - original licence link has changed is not relivant.
60068 * <script type="text/javascript">
60073 * @class Roo.XTemplate
60074 * @extends Roo.Template
60075 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60077 var t = new Roo.XTemplate(
60078 '<select name="{name}">',
60079 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60083 // then append, applying the master template values
60086 * Supported features:
60091 {a_variable} - output encoded.
60092 {a_variable.format:("Y-m-d")} - call a method on the variable
60093 {a_variable:raw} - unencoded output
60094 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60095 {a_variable:this.method_on_template(...)} - call a method on the template object.
60100 <tpl for="a_variable or condition.."></tpl>
60101 <tpl if="a_variable or condition"></tpl>
60102 <tpl exec="some javascript"></tpl>
60103 <tpl name="named_template"></tpl> (experimental)
60105 <tpl for="."></tpl> - just iterate the property..
60106 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60110 Roo.XTemplate = function()
60112 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60119 Roo.extend(Roo.XTemplate, Roo.Template, {
60122 * The various sub templates
60127 * basic tag replacing syntax
60130 * // you can fake an object call by doing this
60134 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60137 * compile the template
60139 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60142 compile: function()
60146 s = ['<tpl>', s, '</tpl>'].join('');
60148 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60149 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60150 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60151 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60152 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60157 while(true == !!(m = s.match(re))){
60158 var forMatch = m[0].match(nameRe),
60159 ifMatch = m[0].match(ifRe),
60160 execMatch = m[0].match(execRe),
60161 namedMatch = m[0].match(namedRe),
60166 name = forMatch && forMatch[1] ? forMatch[1] : '';
60169 // if - puts fn into test..
60170 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60172 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60177 // exec - calls a function... returns empty if true is returned.
60178 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60180 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60188 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60189 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60190 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60193 var uid = namedMatch ? namedMatch[1] : id;
60197 id: namedMatch ? namedMatch[1] : id,
60204 s = s.replace(m[0], '');
60206 s = s.replace(m[0], '{xtpl'+ id + '}');
60211 for(var i = tpls.length-1; i >= 0; --i){
60212 this.compileTpl(tpls[i]);
60213 this.tpls[tpls[i].id] = tpls[i];
60215 this.master = tpls[tpls.length-1];
60219 * same as applyTemplate, except it's done to one of the subTemplates
60220 * when using named templates, you can do:
60222 * var str = pl.applySubTemplate('your-name', values);
60225 * @param {Number} id of the template
60226 * @param {Object} values to apply to template
60227 * @param {Object} parent (normaly the instance of this object)
60229 applySubTemplate : function(id, values, parent)
60233 var t = this.tpls[id];
60237 if(t.test && !t.test.call(this, values, parent)){
60241 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60242 Roo.log(e.toString());
60248 if(t.exec && t.exec.call(this, values, parent)){
60252 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60253 Roo.log(e.toString());
60258 var vs = t.target ? t.target.call(this, values, parent) : values;
60259 parent = t.target ? values : parent;
60260 if(t.target && vs instanceof Array){
60262 for(var i = 0, len = vs.length; i < len; i++){
60263 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60265 return buf.join('');
60267 return t.compiled.call(this, vs, parent);
60269 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60270 Roo.log(e.toString());
60271 Roo.log(t.compiled);
60276 compileTpl : function(tpl)
60278 var fm = Roo.util.Format;
60279 var useF = this.disableFormats !== true;
60280 var sep = Roo.isGecko ? "+" : ",";
60281 var undef = function(str) {
60282 Roo.log("Property not found :" + str);
60286 var fn = function(m, name, format, args)
60288 //Roo.log(arguments);
60289 args = args ? args.replace(/\\'/g,"'") : args;
60290 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60291 if (typeof(format) == 'undefined') {
60292 format= 'htmlEncode';
60294 if (format == 'raw' ) {
60298 if(name.substr(0, 4) == 'xtpl'){
60299 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60302 // build an array of options to determine if value is undefined..
60304 // basically get 'xxxx.yyyy' then do
60305 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60306 // (function () { Roo.log("Property not found"); return ''; })() :
60311 Roo.each(name.split('.'), function(st) {
60312 lookfor += (lookfor.length ? '.': '') + st;
60313 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60316 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60319 if(format && useF){
60321 args = args ? ',' + args : "";
60323 if(format.substr(0, 5) != "this."){
60324 format = "fm." + format + '(';
60326 format = 'this.call("'+ format.substr(5) + '", ';
60330 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60334 // called with xxyx.yuu:(test,test)
60336 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60338 // raw.. - :raw modifier..
60339 return "'"+ sep + udef_st + name + ")"+sep+"'";
60343 // branched to use + in gecko and [].join() in others
60345 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60346 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60349 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60350 body.push(tpl.body.replace(/(\r\n|\n)/g,
60351 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60352 body.push("'].join('');};};");
60353 body = body.join('');
60356 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60358 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60364 applyTemplate : function(values){
60365 return this.master.compiled.call(this, values, {});
60366 //var s = this.subs;
60369 apply : function(){
60370 return this.applyTemplate.apply(this, arguments);
60375 Roo.XTemplate.from = function(el){
60376 el = Roo.getDom(el);
60377 return new Roo.XTemplate(el.value || el.innerHTML);