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 isAndroid = /android/.test(ua),
68 isTouch = (function() {
70 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
71 window.addEventListener('touchstart', function __set_has_touch__ () {
73 window.removeEventListener('touchstart', __set_has_touch__);
75 return false; // no touch on chrome!?
77 document.createEvent("TouchEvent");
84 // remove css image flicker
87 document.execCommand("BackgroundImageCache", false, true);
93 * True if the browser is in strict mode
98 * True if the page is running over SSL
103 * True when the document is fully initialized and ready for action
108 * Turn on debugging output (currently only the factory uses this)
115 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
118 enableGarbageCollector : true,
121 * True to automatically purge event listeners after uncaching an element (defaults to false).
122 * Note: this only happens if enableGarbageCollector is true.
125 enableListenerCollection:false,
128 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
129 * the IE insecure content warning (defaults to javascript:false).
132 SSL_SECURE_URL : "javascript:false",
135 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
136 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
139 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141 emptyFn : function(){},
144 * Copies all the properties of config to obj if they don't already exist.
145 * @param {Object} obj The receiver of the properties
146 * @param {Object} config The source of the properties
147 * @return {Object} returns obj
149 applyIf : function(o, c){
152 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
159 * Applies event listeners to elements by selectors when the document is ready.
160 * The event name is specified with an @ suffix.
163 // add a listener for click on all anchors in element with id foo
164 '#foo a@click' : function(e, t){
168 // add the same listener to multiple selectors (separated by comma BEFORE the @)
169 '#foo a, #bar span.some-class@mouseover' : function(){
174 * @param {Object} obj The list of behaviors to apply
176 addBehaviors : function(o){
178 Roo.onReady(function(){
183 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185 var parts = b.split('@');
186 if(parts[1]){ // for Object prototype breakers
189 cache[s] = Roo.select(s);
191 cache[s].on(parts[1], o[b]);
198 * Generates unique ids. If the element already has an id, it is unchanged
199 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
200 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
201 * @return {String} The generated Id.
203 id : function(el, prefix){
204 prefix = prefix || "roo-gen";
206 var id = prefix + (++idSeed);
207 return el ? (el.id ? el.id : (el.id = id)) : id;
212 * Extends one class with another class and optionally overrides members with the passed literal. This class
213 * also adds the function "override()" to the class that can be used to override
214 * members on an instance.
215 * @param {Object} subclass The class inheriting the functionality
216 * @param {Object} superclass The class being extended
217 * @param {Object} overrides (optional) A literal with members
222 var io = function(o){
227 return function(sb, sp, overrides){
228 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
231 sb = function(){sp.apply(this, arguments);};
233 var F = function(){}, sbp, spp = sp.prototype;
235 sbp = sb.prototype = new F();
239 if(spp.constructor == Object.prototype.constructor){
244 sb.override = function(o){
248 Roo.override(sb, overrides);
254 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256 Roo.override(MyClass, {
257 newMethod1: function(){
260 newMethod2: function(foo){
265 * @param {Object} origclass The class to override
266 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
267 * containing one or more methods.
270 override : function(origclass, overrides){
272 var p = origclass.prototype;
273 for(var method in overrides){
274 p[method] = overrides[method];
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.namespace('Company', 'Company.data');
282 Company.Widget = function() { ... }
283 Company.data.CustomStore = function(config) { ... }
285 * @param {String} namespace1
286 * @param {String} namespace2
287 * @param {String} etc
290 namespace : function(){
291 var a=arguments, o=null, i, j, d, rt;
292 for (i=0; i<a.length; ++i) {
296 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
297 for (j=1; j<d.length; ++j) {
298 o[d[j]]=o[d[j]] || {};
304 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
306 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
307 Roo.factory(conf, Roo.data);
309 * @param {String} classname
310 * @param {String} namespace (optional)
314 factory : function(c, ns)
316 // no xtype, no ns or c.xns - or forced off by c.xns
317 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
320 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
321 if (c.constructor == ns[c.xtype]) {// already created...
325 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
326 var ret = new ns[c.xtype](c);
330 c.xns = false; // prevent recursion..
334 * Logs to console if it can.
336 * @param {String|Object} string
341 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
348 * 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.
352 urlEncode : function(o){
358 var ov = o[key], k = Roo.encodeURIComponent(key);
359 var type = typeof ov;
360 if(type == 'undefined'){
362 }else if(type != "function" && type != "object"){
363 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
364 }else if(ov instanceof Array){
366 for(var i = 0, len = ov.length; i < len; i++) {
367 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
378 * Safe version of encodeURIComponent
379 * @param {String} data
383 encodeURIComponent : function (data)
386 return encodeURIComponent(data);
387 } catch(e) {} // should be an uri encode error.
389 if (data == '' || data == null){
392 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
393 function nibble_to_hex(nibble){
394 var chars = '0123456789ABCDEF';
395 return chars.charAt(nibble);
397 data = data.toString();
399 for(var i=0; i<data.length; i++){
400 var c = data.charCodeAt(i);
401 var bs = new Array();
404 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
405 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
406 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
407 bs[3] = 0x80 | (c & 0x3F);
408 }else if (c > 0x800){
410 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
411 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
412 bs[2] = 0x80 | (c & 0x3F);
415 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
416 bs[1] = 0x80 | (c & 0x3F);
421 for(var j=0; j<bs.length; j++){
423 var hex = nibble_to_hex((b & 0xF0) >>> 4)
424 + nibble_to_hex(b &0x0F);
433 * 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]}.
434 * @param {String} string
435 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
436 * @return {Object} A literal with members
438 urlDecode : function(string, overwrite){
439 if(!string || !string.length){
443 var pairs = string.split('&');
444 var pair, name, value;
445 for(var i = 0, len = pairs.length; i < len; i++){
446 pair = pairs[i].split('=');
447 name = decodeURIComponent(pair[0]);
448 value = decodeURIComponent(pair[1]);
449 if(overwrite !== true){
450 if(typeof obj[name] == "undefined"){
452 }else if(typeof obj[name] == "string"){
453 obj[name] = [obj[name]];
454 obj[name].push(value);
456 obj[name].push(value);
466 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
467 * passed array is not really an array, your function is called once with it.
468 * The supplied function is called with (Object item, Number index, Array allItems).
469 * @param {Array/NodeList/Mixed} array
470 * @param {Function} fn
471 * @param {Object} scope
473 each : function(array, fn, scope){
474 if(typeof array.length == "undefined" || typeof array == "string"){
477 for(var i = 0, len = array.length; i < len; i++){
478 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
483 combine : function(){
484 var as = arguments, l = as.length, r = [];
485 for(var i = 0; i < l; i++){
487 if(a instanceof Array){
489 }else if(a.length !== undefined && !a.substr){
490 r = r.concat(Array.prototype.slice.call(a, 0));
499 * Escapes the passed string for use in a regular expression
500 * @param {String} str
503 escapeRe : function(s) {
504 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
508 callback : function(cb, scope, args, delay){
509 if(typeof cb == "function"){
511 cb.defer(delay, scope, args || []);
513 cb.apply(scope, args || []);
519 * Return the dom node for the passed string (id), dom node, or Roo.Element
520 * @param {String/HTMLElement/Roo.Element} el
521 * @return HTMLElement
523 getDom : function(el){
527 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
531 * Shorthand for {@link Roo.ComponentMgr#get}
533 * @return Roo.Component
535 getCmp : function(id){
536 return Roo.ComponentMgr.get(id);
539 num : function(v, defaultValue){
540 if(typeof v != 'number'){
546 destroy : function(){
547 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
551 as.removeAllListeners();
555 if(typeof as.purgeListeners == 'function'){
558 if(typeof as.destroy == 'function'){
565 // inpired by a similar function in mootools library
567 * Returns the type of object that is passed in. If the object passed in is null or undefined it
568 * return false otherwise it returns one of the following values:<ul>
569 * <li><b>string</b>: If the object passed is a string</li>
570 * <li><b>number</b>: If the object passed is a number</li>
571 * <li><b>boolean</b>: If the object passed is a boolean value</li>
572 * <li><b>function</b>: If the object passed is a function reference</li>
573 * <li><b>object</b>: If the object passed is an object</li>
574 * <li><b>array</b>: If the object passed is an array</li>
575 * <li><b>regexp</b>: If the object passed is a regular expression</li>
576 * <li><b>element</b>: If the object passed is a DOM Element</li>
577 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
578 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
579 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
580 * @param {Mixed} object
584 if(o === undefined || o === null){
591 if(t == 'object' && o.nodeName) {
593 case 1: return 'element';
594 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
597 if(t == 'object' || t == 'function') {
598 switch(o.constructor) {
599 case Array: return 'array';
600 case RegExp: return 'regexp';
602 if(typeof o.length == 'number' && typeof o.item == 'function') {
610 * Returns true if the passed value is null, undefined or an empty string (optional).
611 * @param {Mixed} value The value to test
612 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
615 isEmpty : function(v, allowBlank){
616 return v === null || v === undefined || (!allowBlank ? v === '' : false);
624 isFirefox : isFirefox,
634 isBorderBox : isBorderBox,
636 isWindows : isWindows,
644 isAndroid : isAndroid,
649 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
650 * you may want to set this to true.
653 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
658 * Selects a single element as a Roo Element
659 * This is about as close as you can get to jQuery's $('do crazy stuff')
660 * @param {String} selector The selector/xpath query
661 * @param {Node} root (optional) The start of the query (defaults to document).
662 * @return {Roo.Element}
664 selectNode : function(selector, root)
666 var node = Roo.DomQuery.selectNode(selector,root);
667 return node ? Roo.get(node) : new Roo.Element(false);
675 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
676 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
679 "Roo.bootstrap.dash");
682 * Ext JS Library 1.1.1
683 * Copyright(c) 2006-2007, Ext JS, LLC.
685 * Originally Released Under LGPL - original licence link has changed is not relivant.
688 * <script type="text/javascript">
692 // wrappedn so fnCleanup is not in global scope...
694 function fnCleanUp() {
695 var p = Function.prototype;
696 delete p.createSequence;
698 delete p.createDelegate;
699 delete p.createCallback;
700 delete p.createInterceptor;
702 window.detachEvent("onunload", fnCleanUp);
704 window.attachEvent("onunload", fnCleanUp);
711 * These functions are available on every Function object (any JavaScript function).
713 Roo.apply(Function.prototype, {
715 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
716 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
717 * Will create a function that is bound to those 2 args.
718 * @return {Function} The new function
720 createCallback : function(/*args...*/){
721 // make args available, in function below
722 var args = arguments;
725 return method.apply(window, args);
730 * Creates a delegate (callback) that sets the scope to obj.
731 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
732 * Will create a function that is automatically scoped to this.
733 * @param {Object} obj (optional) The object for which the scope is set
734 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
735 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
736 * if a number the args are inserted at the specified position
737 * @return {Function} The new function
739 createDelegate : function(obj, args, appendArgs){
742 var callArgs = args || arguments;
743 if(appendArgs === true){
744 callArgs = Array.prototype.slice.call(arguments, 0);
745 callArgs = callArgs.concat(args);
746 }else if(typeof appendArgs == "number"){
747 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
748 var applyArgs = [appendArgs, 0].concat(args); // create method call params
749 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
751 return method.apply(obj || window, callArgs);
756 * Calls this function after the number of millseconds specified.
757 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
758 * @param {Object} obj (optional) The object for which the scope is set
759 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761 * if a number the args are inserted at the specified position
762 * @return {Number} The timeout id that can be used with clearTimeout
764 defer : function(millis, obj, args, appendArgs){
765 var fn = this.createDelegate(obj, args, appendArgs);
767 return setTimeout(fn, millis);
773 * Create a combined function call sequence of the original function + the passed function.
774 * The resulting function returns the results of the original function.
775 * The passed fcn is called with the parameters of the original function
776 * @param {Function} fcn The function to sequence
777 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
778 * @return {Function} The new function
780 createSequence : function(fcn, scope){
781 if(typeof fcn != "function"){
786 var retval = method.apply(this || window, arguments);
787 fcn.apply(scope || this || window, arguments);
793 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
794 * The resulting function returns the results of the original function.
795 * The passed fcn is called with the parameters of the original function.
797 * @param {Function} fcn The function to call before the original
798 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
799 * @return {Function} The new function
801 createInterceptor : function(fcn, scope){
802 if(typeof fcn != "function"){
809 if(fcn.apply(scope || this || window, arguments) === false){
812 return method.apply(this || window, arguments);
818 * Ext JS Library 1.1.1
819 * Copyright(c) 2006-2007, Ext JS, LLC.
821 * Originally Released Under LGPL - original licence link has changed is not relivant.
824 * <script type="text/javascript">
827 Roo.applyIf(String, {
832 * Escapes the passed string for ' and \
833 * @param {String} string The string to escape
834 * @return {String} The escaped string
837 escape : function(string) {
838 return string.replace(/('|\\)/g, "\\$1");
842 * Pads the left side of a string with a specified character. This is especially useful
843 * for normalizing number and date strings. Example usage:
845 var s = String.leftPad('123', 5, '0');
846 // s now contains the string: '00123'
848 * @param {String} string The original string
849 * @param {Number} size The total length of the output string
850 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
851 * @return {String} The padded string
854 leftPad : function (val, size, ch) {
855 var result = new String(val);
856 if(ch === null || ch === undefined || ch === '') {
859 while (result.length < size) {
860 result = ch + result;
866 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
867 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
869 var cls = 'my-class', text = 'Some text';
870 var s = String.format('<div class="{0}">{1}</div>', cls, text);
871 // s now contains the string: '<div class="my-class">Some text</div>'
873 * @param {String} string The tokenized string to be formatted
874 * @param {String} value1 The value to replace token {0}
875 * @param {String} value2 Etc...
876 * @return {String} The formatted string
879 format : function(format){
880 var args = Array.prototype.slice.call(arguments, 1);
881 return format.replace(/\{(\d+)\}/g, function(m, i){
882 return Roo.util.Format.htmlEncode(args[i]);
888 * Utility function that allows you to easily switch a string between two alternating values. The passed value
889 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
890 * they are already different, the first value passed in is returned. Note that this method returns the new value
891 * but does not change the current string.
893 // alternate sort directions
894 sort = sort.toggle('ASC', 'DESC');
896 // instead of conditional logic:
897 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
899 * @param {String} value The value to compare to the current string
900 * @param {String} other The new value to use if the string already equals the first value passed in
901 * @return {String} The new value
904 String.prototype.toggle = function(value, other){
905 return this == value ? other : value;
908 * Ext JS Library 1.1.1
909 * Copyright(c) 2006-2007, Ext JS, LLC.
911 * Originally Released Under LGPL - original licence link has changed is not relivant.
914 * <script type="text/javascript">
920 Roo.applyIf(Number.prototype, {
922 * Checks whether or not the current number is within a desired range. If the number is already within the
923 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
924 * exceeded. Note that this method returns the constrained value but does not change the current number.
925 * @param {Number} min The minimum number in the range
926 * @param {Number} max The maximum number in the range
927 * @return {Number} The constrained value if outside the range, otherwise the current value
929 constrain : function(min, max){
930 return Math.min(Math.max(this, min), max);
934 * Ext JS Library 1.1.1
935 * Copyright(c) 2006-2007, Ext JS, LLC.
937 * Originally Released Under LGPL - original licence link has changed is not relivant.
940 * <script type="text/javascript">
945 Roo.applyIf(Array.prototype, {
948 * Checks whether or not the specified object exists in the array.
949 * @param {Object} o The object to check for
950 * @return {Number} The index of o in the array (or -1 if it is not found)
952 indexOf : function(o){
953 for (var i = 0, len = this.length; i < len; i++){
954 if(this[i] == o) { return i; }
960 * Removes the specified object from the array. If the object is not found nothing happens.
961 * @param {Object} o The object to remove
963 remove : function(o){
964 var index = this.indexOf(o);
966 this.splice(index, 1);
970 * Map (JS 1.6 compatibility)
971 * @param {Function} function to call
975 var len = this.length >>> 0;
976 if (typeof fun != "function") {
977 throw new TypeError();
979 var res = new Array(len);
980 var thisp = arguments[1];
981 for (var i = 0; i < len; i++)
984 res[i] = fun.call(thisp, this[i], i, this);
997 * Ext JS Library 1.1.1
998 * Copyright(c) 2006-2007, Ext JS, LLC.
1000 * Originally Released Under LGPL - original licence link has changed is not relivant.
1003 * <script type="text/javascript">
1009 * The date parsing and format syntax is a subset of
1010 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1011 * supported will provide results equivalent to their PHP versions.
1013 * Following is the list of all currently supported formats:
1016 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1018 Format Output Description
1019 ------ ---------- --------------------------------------------------------------
1020 d 10 Day of the month, 2 digits with leading zeros
1021 D Wed A textual representation of a day, three letters
1022 j 10 Day of the month without leading zeros
1023 l Wednesday A full textual representation of the day of the week
1024 S th English ordinal day of month suffix, 2 chars (use with j)
1025 w 3 Numeric representation of the day of the week
1026 z 9 The julian date, or day of the year (0-365)
1027 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1028 F January A full textual representation of the month
1029 m 01 Numeric representation of a month, with leading zeros
1030 M Jan Month name abbreviation, three letters
1031 n 1 Numeric representation of a month, without leading zeros
1032 t 31 Number of days in the given month
1033 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1034 Y 2007 A full numeric representation of a year, 4 digits
1035 y 07 A two digit representation of a year
1036 a pm Lowercase Ante meridiem and Post meridiem
1037 A PM Uppercase Ante meridiem and Post meridiem
1038 g 3 12-hour format of an hour without leading zeros
1039 G 15 24-hour format of an hour without leading zeros
1040 h 03 12-hour format of an hour with leading zeros
1041 H 15 24-hour format of an hour with leading zeros
1042 i 05 Minutes with leading zeros
1043 s 01 Seconds, with leading zeros
1044 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1045 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1046 T CST Timezone setting of the machine running the code
1047 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1050 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1052 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1053 document.write(dt.format('Y-m-d')); //2007-01-10
1054 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1055 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
1058 * Here are some standard date/time patterns that you might find helpful. They
1059 * are not part of the source of Date.js, but to use them you can simply copy this
1060 * block of code into any script that is included after Date.js and they will also become
1061 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1064 ISO8601Long:"Y-m-d H:i:s",
1065 ISO8601Short:"Y-m-d",
1067 LongDate: "l, F d, Y",
1068 FullDateTime: "l, F d, Y g:i:s A",
1071 LongTime: "g:i:s A",
1072 SortableDateTime: "Y-m-d\\TH:i:s",
1073 UniversalSortableDateTime: "Y-m-d H:i:sO",
1080 var dt = new Date();
1081 document.write(dt.format(Date.patterns.ShortDate));
1086 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1087 * They generate precompiled functions from date formats instead of parsing and
1088 * processing the pattern every time you format a date. These functions are available
1089 * on every Date object (any javascript function).
1091 * The original article and download are here:
1092 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1099 Returns the number of milliseconds between this date and date
1100 @param {Date} date (optional) Defaults to now
1101 @return {Number} The diff in milliseconds
1102 @member Date getElapsed
1104 Date.prototype.getElapsed = function(date) {
1105 return Math.abs((date || new Date()).getTime()-this.getTime());
1107 // was in date file..
1111 Date.parseFunctions = {count:0};
1113 Date.parseRegexes = [];
1115 Date.formatFunctions = {count:0};
1118 Date.prototype.dateFormat = function(format) {
1119 if (Date.formatFunctions[format] == null) {
1120 Date.createNewFormat(format);
1122 var func = Date.formatFunctions[format];
1123 return this[func]();
1128 * Formats a date given the supplied format string
1129 * @param {String} format The format string
1130 * @return {String} The formatted date
1133 Date.prototype.format = Date.prototype.dateFormat;
1136 Date.createNewFormat = function(format) {
1137 var funcName = "format" + Date.formatFunctions.count++;
1138 Date.formatFunctions[format] = funcName;
1139 var code = "Date.prototype." + funcName + " = function(){return ";
1140 var special = false;
1142 for (var i = 0; i < format.length; ++i) {
1143 ch = format.charAt(i);
1144 if (!special && ch == "\\") {
1149 code += "'" + String.escape(ch) + "' + ";
1152 code += Date.getFormatCode(ch);
1155 /** eval:var:zzzzzzzzzzzzz */
1156 eval(code.substring(0, code.length - 3) + ";}");
1160 Date.getFormatCode = function(character) {
1161 switch (character) {
1163 return "String.leftPad(this.getDate(), 2, '0') + ";
1165 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1167 return "this.getDate() + ";
1169 return "Date.dayNames[this.getDay()] + ";
1171 return "this.getSuffix() + ";
1173 return "this.getDay() + ";
1175 return "this.getDayOfYear() + ";
1177 return "this.getWeekOfYear() + ";
1179 return "Date.monthNames[this.getMonth()] + ";
1181 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1183 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1185 return "(this.getMonth() + 1) + ";
1187 return "this.getDaysInMonth() + ";
1189 return "(this.isLeapYear() ? 1 : 0) + ";
1191 return "this.getFullYear() + ";
1193 return "('' + this.getFullYear()).substring(2, 4) + ";
1195 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1197 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1199 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1201 return "this.getHours() + ";
1203 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1205 return "String.leftPad(this.getHours(), 2, '0') + ";
1207 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1209 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1211 return "this.getGMTOffset() + ";
1213 return "this.getGMTColonOffset() + ";
1215 return "this.getTimezone() + ";
1217 return "(this.getTimezoneOffset() * -60) + ";
1219 return "'" + String.escape(character) + "' + ";
1224 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1225 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1226 * the date format that is not specified will default to the current date value for that part. Time parts can also
1227 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1228 * string or the parse operation will fail.
1231 //dt = Fri May 25 2007 (current date)
1232 var dt = new Date();
1234 //dt = Thu May 25 2006 (today's month/day in 2006)
1235 dt = Date.parseDate("2006", "Y");
1237 //dt = Sun Jan 15 2006 (all date parts specified)
1238 dt = Date.parseDate("2006-1-15", "Y-m-d");
1240 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1241 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1243 * @param {String} input The unparsed date as a string
1244 * @param {String} format The format the date is in
1245 * @return {Date} The parsed date
1248 Date.parseDate = function(input, format) {
1249 if (Date.parseFunctions[format] == null) {
1250 Date.createParser(format);
1252 var func = Date.parseFunctions[format];
1253 return Date[func](input);
1259 Date.createParser = function(format) {
1260 var funcName = "parse" + Date.parseFunctions.count++;
1261 var regexNum = Date.parseRegexes.length;
1262 var currentGroup = 1;
1263 Date.parseFunctions[format] = funcName;
1265 var code = "Date." + funcName + " = function(input){\n"
1266 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1267 + "var d = new Date();\n"
1268 + "y = d.getFullYear();\n"
1269 + "m = d.getMonth();\n"
1270 + "d = d.getDate();\n"
1271 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1272 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1273 + "if (results && results.length > 0) {";
1276 var special = false;
1278 for (var i = 0; i < format.length; ++i) {
1279 ch = format.charAt(i);
1280 if (!special && ch == "\\") {
1285 regex += String.escape(ch);
1288 var obj = Date.formatCodeToRegex(ch, currentGroup);
1289 currentGroup += obj.g;
1291 if (obj.g && obj.c) {
1297 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1298 + "{v = new Date(y, m, d, h, i, s);}\n"
1299 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1300 + "{v = new Date(y, m, d, h, i);}\n"
1301 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1302 + "{v = new Date(y, m, d, h);}\n"
1303 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1304 + "{v = new Date(y, m, d);}\n"
1305 + "else if (y >= 0 && m >= 0)\n"
1306 + "{v = new Date(y, m);}\n"
1307 + "else if (y >= 0)\n"
1308 + "{v = new Date(y);}\n"
1309 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1310 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1311 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1314 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1315 /** eval:var:zzzzzzzzzzzzz */
1320 Date.formatCodeToRegex = function(character, currentGroup) {
1321 switch (character) {
1325 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1328 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1329 s:"(\\d{1,2})"}; // day of month without leading zeroes
1332 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1333 s:"(\\d{2})"}; // day of month with leading zeroes
1337 s:"(?:" + Date.dayNames.join("|") + ")"};
1341 s:"(?:st|nd|rd|th)"};
1356 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1357 s:"(" + Date.monthNames.join("|") + ")"};
1360 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1361 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1364 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1365 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1368 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1369 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1380 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1384 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1385 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1389 c:"if (results[" + currentGroup + "] == 'am') {\n"
1390 + "if (h == 12) { h = 0; }\n"
1391 + "} else { if (h < 12) { h += 12; }}",
1395 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1396 + "if (h == 12) { h = 0; }\n"
1397 + "} else { if (h < 12) { h += 12; }}",
1402 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1403 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1407 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1408 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1411 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1415 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1420 "o = results[", currentGroup, "];\n",
1421 "var sn = o.substring(0,1);\n", // get + / - sign
1422 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1423 "var mn = o.substring(3,5) % 60;\n", // get minutes
1424 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1425 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1427 s:"([+\-]\\d{2,4})"};
1433 "o = results[", currentGroup, "];\n",
1434 "var sn = o.substring(0,1);\n",
1435 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1436 "var mn = o.substring(4,6) % 60;\n",
1437 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1438 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1444 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1447 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1448 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1449 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1453 s:String.escape(character)};
1458 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1459 * @return {String} The abbreviated timezone name (e.g. 'CST')
1461 Date.prototype.getTimezone = function() {
1462 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1466 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1467 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1469 Date.prototype.getGMTOffset = function() {
1470 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1471 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1476 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1477 * @return {String} 2-characters representing hours and 2-characters representing minutes
1478 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1480 Date.prototype.getGMTColonOffset = function() {
1481 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1482 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1484 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1488 * Get the numeric day number of the year, adjusted for leap year.
1489 * @return {Number} 0 through 364 (365 in leap years)
1491 Date.prototype.getDayOfYear = function() {
1493 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1494 for (var i = 0; i < this.getMonth(); ++i) {
1495 num += Date.daysInMonth[i];
1497 return num + this.getDate() - 1;
1501 * Get the string representation of the numeric week number of the year
1502 * (equivalent to the format specifier 'W').
1503 * @return {String} '00' through '52'
1505 Date.prototype.getWeekOfYear = function() {
1506 // Skip to Thursday of this week
1507 var now = this.getDayOfYear() + (4 - this.getDay());
1508 // Find the first Thursday of the year
1509 var jan1 = new Date(this.getFullYear(), 0, 1);
1510 var then = (7 - jan1.getDay() + 4);
1511 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1515 * Whether or not the current date is in a leap year.
1516 * @return {Boolean} True if the current date is in a leap year, else false
1518 Date.prototype.isLeapYear = function() {
1519 var year = this.getFullYear();
1520 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1524 * Get the first day of the current month, adjusted for leap year. The returned value
1525 * is the numeric day index within the week (0-6) which can be used in conjunction with
1526 * the {@link #monthNames} array to retrieve the textual day name.
1529 var dt = new Date('1/10/2007');
1530 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1532 * @return {Number} The day number (0-6)
1534 Date.prototype.getFirstDayOfMonth = function() {
1535 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1536 return (day < 0) ? (day + 7) : day;
1540 * Get the last day of the current month, adjusted for leap year. The returned value
1541 * is the numeric day index within the week (0-6) which can be used in conjunction with
1542 * the {@link #monthNames} array to retrieve the textual day name.
1545 var dt = new Date('1/10/2007');
1546 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1548 * @return {Number} The day number (0-6)
1550 Date.prototype.getLastDayOfMonth = function() {
1551 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1552 return (day < 0) ? (day + 7) : day;
1557 * Get the first date of this date's month
1560 Date.prototype.getFirstDateOfMonth = function() {
1561 return new Date(this.getFullYear(), this.getMonth(), 1);
1565 * Get the last date of this date's month
1568 Date.prototype.getLastDateOfMonth = function() {
1569 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1572 * Get the number of days in the current month, adjusted for leap year.
1573 * @return {Number} The number of days in the month
1575 Date.prototype.getDaysInMonth = function() {
1576 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1577 return Date.daysInMonth[this.getMonth()];
1581 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1582 * @return {String} 'st, 'nd', 'rd' or 'th'
1584 Date.prototype.getSuffix = function() {
1585 switch (this.getDate()) {
1602 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1605 * An array of textual month names.
1606 * Override these values for international dates, for example...
1607 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1626 * An array of textual day names.
1627 * Override these values for international dates, for example...
1628 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1644 Date.monthNumbers = {
1659 * Creates and returns a new Date instance with the exact same date value as the called instance.
1660 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1661 * variable will also be changed. When the intention is to create a new variable that will not
1662 * modify the original instance, you should create a clone.
1664 * Example of correctly cloning a date:
1667 var orig = new Date('10/1/2006');
1670 document.write(orig); //returns 'Thu Oct 05 2006'!
1673 var orig = new Date('10/1/2006');
1674 var copy = orig.clone();
1676 document.write(orig); //returns 'Thu Oct 01 2006'
1678 * @return {Date} The new Date instance
1680 Date.prototype.clone = function() {
1681 return new Date(this.getTime());
1685 * Clears any time information from this date
1686 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1687 @return {Date} this or the clone
1689 Date.prototype.clearTime = function(clone){
1691 return this.clone().clearTime();
1696 this.setMilliseconds(0);
1701 // safari setMonth is broken -- check that this is only donw once...
1702 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1703 Date.brokenSetMonth = Date.prototype.setMonth;
1704 Date.prototype.setMonth = function(num){
1706 var n = Math.ceil(-num);
1707 var back_year = Math.ceil(n/12);
1708 var month = (n % 12) ? 12 - n % 12 : 0 ;
1709 this.setFullYear(this.getFullYear() - back_year);
1710 return Date.brokenSetMonth.call(this, month);
1712 return Date.brokenSetMonth.apply(this, arguments);
1717 /** Date interval constant
1721 /** Date interval constant
1725 /** Date interval constant
1729 /** Date interval constant
1733 /** Date interval constant
1737 /** Date interval constant
1741 /** Date interval constant
1747 * Provides a convenient method of performing basic date arithmetic. This method
1748 * does not modify the Date instance being called - it creates and returns
1749 * a new Date instance containing the resulting date value.
1754 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1755 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1757 //Negative values will subtract correctly:
1758 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1759 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1761 //You can even chain several calls together in one line!
1762 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1763 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1766 * @param {String} interval A valid date interval enum value
1767 * @param {Number} value The amount to add to the current date
1768 * @return {Date} The new Date instance
1770 Date.prototype.add = function(interval, value){
1771 var d = this.clone();
1772 if (!interval || value === 0) { return d; }
1773 switch(interval.toLowerCase()){
1775 d.setMilliseconds(this.getMilliseconds() + value);
1778 d.setSeconds(this.getSeconds() + value);
1781 d.setMinutes(this.getMinutes() + value);
1784 d.setHours(this.getHours() + value);
1787 d.setDate(this.getDate() + value);
1790 var day = this.getDate();
1792 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1795 d.setMonth(this.getMonth() + value);
1798 d.setFullYear(this.getFullYear() + value);
1805 * Ext JS Library 1.1.1
1806 * Copyright(c) 2006-2007, Ext JS, LLC.
1808 * Originally Released Under LGPL - original licence link has changed is not relivant.
1811 * <script type="text/javascript">
1815 * @class Roo.lib.Dom
1818 * Dom utils (from YIU afaik)
1823 * Get the view width
1824 * @param {Boolean} full True will get the full document, otherwise it's the view width
1825 * @return {Number} The width
1828 getViewWidth : function(full) {
1829 return full ? this.getDocumentWidth() : this.getViewportWidth();
1832 * Get the view height
1833 * @param {Boolean} full True will get the full document, otherwise it's the view height
1834 * @return {Number} The height
1836 getViewHeight : function(full) {
1837 return full ? this.getDocumentHeight() : this.getViewportHeight();
1840 getDocumentHeight: function() {
1841 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1842 return Math.max(scrollHeight, this.getViewportHeight());
1845 getDocumentWidth: function() {
1846 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1847 return Math.max(scrollWidth, this.getViewportWidth());
1850 getViewportHeight: function() {
1851 var height = self.innerHeight;
1852 var mode = document.compatMode;
1854 if ((mode || Roo.isIE) && !Roo.isOpera) {
1855 height = (mode == "CSS1Compat") ?
1856 document.documentElement.clientHeight :
1857 document.body.clientHeight;
1863 getViewportWidth: function() {
1864 var width = self.innerWidth;
1865 var mode = document.compatMode;
1867 if (mode || Roo.isIE) {
1868 width = (mode == "CSS1Compat") ?
1869 document.documentElement.clientWidth :
1870 document.body.clientWidth;
1875 isAncestor : function(p, c) {
1882 if (p.contains && !Roo.isSafari) {
1883 return p.contains(c);
1884 } else if (p.compareDocumentPosition) {
1885 return !!(p.compareDocumentPosition(c) & 16);
1887 var parent = c.parentNode;
1892 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1895 parent = parent.parentNode;
1901 getRegion : function(el) {
1902 return Roo.lib.Region.getRegion(el);
1905 getY : function(el) {
1906 return this.getXY(el)[1];
1909 getX : function(el) {
1910 return this.getXY(el)[0];
1913 getXY : function(el) {
1914 var p, pe, b, scroll, bd = document.body;
1915 el = Roo.getDom(el);
1916 var fly = Roo.lib.AnimBase.fly;
1917 if (el.getBoundingClientRect) {
1918 b = el.getBoundingClientRect();
1919 scroll = fly(document).getScroll();
1920 return [b.left + scroll.left, b.top + scroll.top];
1926 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1933 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1940 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1941 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1948 if (p != el && pe.getStyle('overflow') != 'visible') {
1956 if (Roo.isSafari && hasAbsolute) {
1961 if (Roo.isGecko && !hasAbsolute) {
1963 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1964 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1968 while (p && p != bd) {
1969 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1981 setXY : function(el, xy) {
1982 el = Roo.fly(el, '_setXY');
1984 var pts = el.translatePoints(xy);
1985 if (xy[0] !== false) {
1986 el.dom.style.left = pts.left + "px";
1988 if (xy[1] !== false) {
1989 el.dom.style.top = pts.top + "px";
1993 setX : function(el, x) {
1994 this.setXY(el, [x, false]);
1997 setY : function(el, y) {
1998 this.setXY(el, [false, y]);
2002 * Portions of this file are based on pieces of Yahoo User Interface Library
2003 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2004 * YUI licensed under the BSD License:
2005 * http://developer.yahoo.net/yui/license.txt
2006 * <script type="text/javascript">
2010 Roo.lib.Event = function() {
2011 var loadComplete = false;
2013 var unloadListeners = [];
2015 var onAvailStack = [];
2017 var lastError = null;
2030 startInterval: function() {
2031 if (!this._interval) {
2033 var callback = function() {
2034 self._tryPreloadAttach();
2036 this._interval = setInterval(callback, this.POLL_INTERVAL);
2041 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2042 onAvailStack.push({ id: p_id,
2045 override: p_override,
2046 checkReady: false });
2048 retryCount = this.POLL_RETRYS;
2049 this.startInterval();
2053 addListener: function(el, eventName, fn) {
2054 el = Roo.getDom(el);
2059 if ("unload" == eventName) {
2060 unloadListeners[unloadListeners.length] =
2061 [el, eventName, fn];
2065 var wrappedFn = function(e) {
2066 return fn(Roo.lib.Event.getEvent(e));
2069 var li = [el, eventName, fn, wrappedFn];
2071 var index = listeners.length;
2072 listeners[index] = li;
2074 this.doAdd(el, eventName, wrappedFn, false);
2080 removeListener: function(el, eventName, fn) {
2083 el = Roo.getDom(el);
2086 return this.purgeElement(el, false, eventName);
2090 if ("unload" == eventName) {
2092 for (i = 0,len = unloadListeners.length; i < len; i++) {
2093 var li = unloadListeners[i];
2096 li[1] == eventName &&
2098 unloadListeners.splice(i, 1);
2106 var cacheItem = null;
2109 var index = arguments[3];
2111 if ("undefined" == typeof index) {
2112 index = this._getCacheIndex(el, eventName, fn);
2116 cacheItem = listeners[index];
2119 if (!el || !cacheItem) {
2123 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2125 delete listeners[index][this.WFN];
2126 delete listeners[index][this.FN];
2127 listeners.splice(index, 1);
2134 getTarget: function(ev, resolveTextNode) {
2135 ev = ev.browserEvent || ev;
2136 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2137 var t = ev.target || ev.srcElement;
2138 return this.resolveTextNode(t);
2142 resolveTextNode: function(node) {
2143 if (Roo.isSafari && node && 3 == node.nodeType) {
2144 return node.parentNode;
2151 getPageX: function(ev) {
2152 ev = ev.browserEvent || ev;
2153 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2155 if (!x && 0 !== x) {
2156 x = ev.clientX || 0;
2159 x += this.getScroll()[1];
2167 getPageY: function(ev) {
2168 ev = ev.browserEvent || ev;
2169 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2171 if (!y && 0 !== y) {
2172 y = ev.clientY || 0;
2175 y += this.getScroll()[0];
2184 getXY: function(ev) {
2185 ev = ev.browserEvent || ev;
2186 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2187 return [this.getPageX(ev), this.getPageY(ev)];
2191 getRelatedTarget: function(ev) {
2192 ev = ev.browserEvent || ev;
2193 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2194 var t = ev.relatedTarget;
2196 if (ev.type == "mouseout") {
2198 } else if (ev.type == "mouseover") {
2203 return this.resolveTextNode(t);
2207 getTime: function(ev) {
2208 ev = ev.browserEvent || ev;
2209 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2211 var t = new Date().getTime();
2215 this.lastError = ex;
2224 stopEvent: function(ev) {
2225 this.stopPropagation(ev);
2226 this.preventDefault(ev);
2230 stopPropagation: function(ev) {
2231 ev = ev.browserEvent || ev;
2232 if (ev.stopPropagation) {
2233 ev.stopPropagation();
2235 ev.cancelBubble = true;
2240 preventDefault: function(ev) {
2241 ev = ev.browserEvent || ev;
2242 if(ev.preventDefault) {
2243 ev.preventDefault();
2245 ev.returnValue = false;
2250 getEvent: function(e) {
2251 var ev = e || window.event;
2253 var c = this.getEvent.caller;
2255 ev = c.arguments[0];
2256 if (ev && Event == ev.constructor) {
2266 getCharCode: function(ev) {
2267 ev = ev.browserEvent || ev;
2268 return ev.charCode || ev.keyCode || 0;
2272 _getCacheIndex: function(el, eventName, fn) {
2273 for (var i = 0,len = listeners.length; i < len; ++i) {
2274 var li = listeners[i];
2276 li[this.FN] == fn &&
2277 li[this.EL] == el &&
2278 li[this.TYPE] == eventName) {
2290 getEl: function(id) {
2291 return document.getElementById(id);
2295 clearCache: function() {
2299 _load: function(e) {
2300 loadComplete = true;
2301 var EU = Roo.lib.Event;
2305 EU.doRemove(window, "load", EU._load);
2310 _tryPreloadAttach: function() {
2319 var tryAgain = !loadComplete;
2321 tryAgain = (retryCount > 0);
2326 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2327 var item = onAvailStack[i];
2329 var el = this.getEl(item.id);
2332 if (!item.checkReady ||
2335 (document && document.body)) {
2338 if (item.override) {
2339 if (item.override === true) {
2342 scope = item.override;
2345 item.fn.call(scope, item.obj);
2346 onAvailStack[i] = null;
2349 notAvail.push(item);
2354 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2358 this.startInterval();
2360 clearInterval(this._interval);
2361 this._interval = null;
2364 this.locked = false;
2371 purgeElement: function(el, recurse, eventName) {
2372 var elListeners = this.getListeners(el, eventName);
2374 for (var i = 0,len = elListeners.length; i < len; ++i) {
2375 var l = elListeners[i];
2376 this.removeListener(el, l.type, l.fn);
2380 if (recurse && el && el.childNodes) {
2381 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2382 this.purgeElement(el.childNodes[i], recurse, eventName);
2388 getListeners: function(el, eventName) {
2389 var results = [], searchLists;
2391 searchLists = [listeners, unloadListeners];
2392 } else if (eventName == "unload") {
2393 searchLists = [unloadListeners];
2395 searchLists = [listeners];
2398 for (var j = 0; j < searchLists.length; ++j) {
2399 var searchList = searchLists[j];
2400 if (searchList && searchList.length > 0) {
2401 for (var i = 0,len = searchList.length; i < len; ++i) {
2402 var l = searchList[i];
2403 if (l && l[this.EL] === el &&
2404 (!eventName || eventName === l[this.TYPE])) {
2409 adjust: l[this.ADJ_SCOPE],
2417 return (results.length) ? results : null;
2421 _unload: function(e) {
2423 var EU = Roo.lib.Event, i, j, l, len, index;
2425 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2426 l = unloadListeners[i];
2429 if (l[EU.ADJ_SCOPE]) {
2430 if (l[EU.ADJ_SCOPE] === true) {
2433 scope = l[EU.ADJ_SCOPE];
2436 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2437 unloadListeners[i] = null;
2443 unloadListeners = null;
2445 if (listeners && listeners.length > 0) {
2446 j = listeners.length;
2449 l = listeners[index];
2451 EU.removeListener(l[EU.EL], l[EU.TYPE],
2461 EU.doRemove(window, "unload", EU._unload);
2466 getScroll: function() {
2467 var dd = document.documentElement, db = document.body;
2468 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2469 return [dd.scrollTop, dd.scrollLeft];
2471 return [db.scrollTop, db.scrollLeft];
2478 doAdd: function () {
2479 if (window.addEventListener) {
2480 return function(el, eventName, fn, capture) {
2481 el.addEventListener(eventName, fn, (capture));
2483 } else if (window.attachEvent) {
2484 return function(el, eventName, fn, capture) {
2485 el.attachEvent("on" + eventName, fn);
2494 doRemove: function() {
2495 if (window.removeEventListener) {
2496 return function (el, eventName, fn, capture) {
2497 el.removeEventListener(eventName, fn, (capture));
2499 } else if (window.detachEvent) {
2500 return function (el, eventName, fn) {
2501 el.detachEvent("on" + eventName, fn);
2513 var E = Roo.lib.Event;
2514 E.on = E.addListener;
2515 E.un = E.removeListener;
2517 if (document && document.body) {
2520 E.doAdd(window, "load", E._load);
2522 E.doAdd(window, "unload", E._unload);
2523 E._tryPreloadAttach();
2527 * Portions of this file are based on pieces of Yahoo User Interface Library
2528 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2529 * YUI licensed under the BSD License:
2530 * http://developer.yahoo.net/yui/license.txt
2531 * <script type="text/javascript">
2537 * @class Roo.lib.Ajax
2544 request : function(method, uri, cb, data, options) {
2546 var hs = options.headers;
2549 if(hs.hasOwnProperty(h)){
2550 this.initHeader(h, hs[h], false);
2554 if(options.xmlData){
2555 this.initHeader('Content-Type', 'text/xml', false);
2557 data = options.xmlData;
2561 return this.asyncRequest(method, uri, cb, data);
2564 serializeForm : function(form) {
2565 if(typeof form == 'string') {
2566 form = (document.getElementById(form) || document.forms[form]);
2569 var el, name, val, disabled, data = '', hasSubmit = false;
2570 for (var i = 0; i < form.elements.length; i++) {
2571 el = form.elements[i];
2572 disabled = form.elements[i].disabled;
2573 name = form.elements[i].name;
2574 val = form.elements[i].value;
2576 if (!disabled && name){
2580 case 'select-multiple':
2581 for (var j = 0; j < el.options.length; j++) {
2582 if (el.options[j].selected) {
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2587 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2595 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2608 if(hasSubmit == false) {
2609 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2614 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2619 data = data.substr(0, data.length - 1);
2627 useDefaultHeader:true,
2629 defaultPostHeader:'application/x-www-form-urlencoded',
2631 useDefaultXhrHeader:true,
2633 defaultXhrHeader:'XMLHttpRequest',
2635 hasDefaultHeaders:true,
2647 setProgId:function(id)
2649 this.activeX.unshift(id);
2652 setDefaultPostHeader:function(b)
2654 this.useDefaultHeader = b;
2657 setDefaultXhrHeader:function(b)
2659 this.useDefaultXhrHeader = b;
2662 setPollingInterval:function(i)
2664 if (typeof i == 'number' && isFinite(i)) {
2665 this.pollInterval = i;
2669 createXhrObject:function(transactionId)
2675 http = new XMLHttpRequest();
2677 obj = { conn:http, tId:transactionId };
2681 for (var i = 0; i < this.activeX.length; ++i) {
2685 http = new ActiveXObject(this.activeX[i]);
2687 obj = { conn:http, tId:transactionId };
2700 getConnectionObject:function()
2703 var tId = this.transactionId;
2707 o = this.createXhrObject(tId);
2709 this.transactionId++;
2720 asyncRequest:function(method, uri, callback, postData)
2722 var o = this.getConnectionObject();
2728 o.conn.open(method, uri, true);
2730 if (this.useDefaultXhrHeader) {
2731 if (!this.defaultHeaders['X-Requested-With']) {
2732 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2736 if(postData && this.useDefaultHeader){
2737 this.initHeader('Content-Type', this.defaultPostHeader);
2740 if (this.hasDefaultHeaders || this.hasHeaders) {
2744 this.handleReadyState(o, callback);
2745 o.conn.send(postData || null);
2751 handleReadyState:function(o, callback)
2755 if (callback && callback.timeout) {
2757 this.timeout[o.tId] = window.setTimeout(function() {
2758 oConn.abort(o, callback, true);
2759 }, callback.timeout);
2762 this.poll[o.tId] = window.setInterval(
2764 if (o.conn && o.conn.readyState == 4) {
2765 window.clearInterval(oConn.poll[o.tId]);
2766 delete oConn.poll[o.tId];
2768 if(callback && callback.timeout) {
2769 window.clearTimeout(oConn.timeout[o.tId]);
2770 delete oConn.timeout[o.tId];
2773 oConn.handleTransactionResponse(o, callback);
2776 , this.pollInterval);
2779 handleTransactionResponse:function(o, callback, isAbort)
2783 this.releaseObject(o);
2787 var httpStatus, responseObject;
2791 if (o.conn.status !== undefined && o.conn.status != 0) {
2792 httpStatus = o.conn.status;
2804 if (httpStatus >= 200 && httpStatus < 300) {
2805 responseObject = this.createResponseObject(o, callback.argument);
2806 if (callback.success) {
2807 if (!callback.scope) {
2808 callback.success(responseObject);
2813 callback.success.apply(callback.scope, [responseObject]);
2818 switch (httpStatus) {
2826 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2827 if (callback.failure) {
2828 if (!callback.scope) {
2829 callback.failure(responseObject);
2832 callback.failure.apply(callback.scope, [responseObject]);
2837 responseObject = this.createResponseObject(o, callback.argument);
2838 if (callback.failure) {
2839 if (!callback.scope) {
2840 callback.failure(responseObject);
2843 callback.failure.apply(callback.scope, [responseObject]);
2849 this.releaseObject(o);
2850 responseObject = null;
2853 createResponseObject:function(o, callbackArg)
2860 var headerStr = o.conn.getAllResponseHeaders();
2861 var header = headerStr.split('\n');
2862 for (var i = 0; i < header.length; i++) {
2863 var delimitPos = header[i].indexOf(':');
2864 if (delimitPos != -1) {
2865 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2873 obj.status = o.conn.status;
2874 obj.statusText = o.conn.statusText;
2875 obj.getResponseHeader = headerObj;
2876 obj.getAllResponseHeaders = headerStr;
2877 obj.responseText = o.conn.responseText;
2878 obj.responseXML = o.conn.responseXML;
2880 if (typeof callbackArg !== undefined) {
2881 obj.argument = callbackArg;
2887 createExceptionObject:function(tId, callbackArg, isAbort)
2890 var COMM_ERROR = 'communication failure';
2891 var ABORT_CODE = -1;
2892 var ABORT_ERROR = 'transaction aborted';
2898 obj.status = ABORT_CODE;
2899 obj.statusText = ABORT_ERROR;
2902 obj.status = COMM_CODE;
2903 obj.statusText = COMM_ERROR;
2907 obj.argument = callbackArg;
2913 initHeader:function(label, value, isDefault)
2915 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2917 if (headerObj[label] === undefined) {
2918 headerObj[label] = value;
2923 headerObj[label] = value + "," + headerObj[label];
2927 this.hasDefaultHeaders = true;
2930 this.hasHeaders = true;
2935 setHeader:function(o)
2937 if (this.hasDefaultHeaders) {
2938 for (var prop in this.defaultHeaders) {
2939 if (this.defaultHeaders.hasOwnProperty(prop)) {
2940 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2945 if (this.hasHeaders) {
2946 for (var prop in this.headers) {
2947 if (this.headers.hasOwnProperty(prop)) {
2948 o.conn.setRequestHeader(prop, this.headers[prop]);
2952 this.hasHeaders = false;
2956 resetDefaultHeaders:function() {
2957 delete this.defaultHeaders;
2958 this.defaultHeaders = {};
2959 this.hasDefaultHeaders = false;
2962 abort:function(o, callback, isTimeout)
2964 if(this.isCallInProgress(o)) {
2966 window.clearInterval(this.poll[o.tId]);
2967 delete this.poll[o.tId];
2969 delete this.timeout[o.tId];
2972 this.handleTransactionResponse(o, callback, true);
2982 isCallInProgress:function(o)
2985 return o.conn.readyState != 4 && o.conn.readyState != 0;
2994 releaseObject:function(o)
3003 'MSXML2.XMLHTTP.3.0',
3011 * Portions of this file are based on pieces of Yahoo User Interface Library
3012 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3013 * YUI licensed under the BSD License:
3014 * http://developer.yahoo.net/yui/license.txt
3015 * <script type="text/javascript">
3019 Roo.lib.Region = function(t, r, b, l) {
3029 Roo.lib.Region.prototype = {
3030 contains : function(region) {
3031 return ( region.left >= this.left &&
3032 region.right <= this.right &&
3033 region.top >= this.top &&
3034 region.bottom <= this.bottom );
3038 getArea : function() {
3039 return ( (this.bottom - this.top) * (this.right - this.left) );
3042 intersect : function(region) {
3043 var t = Math.max(this.top, region.top);
3044 var r = Math.min(this.right, region.right);
3045 var b = Math.min(this.bottom, region.bottom);
3046 var l = Math.max(this.left, region.left);
3048 if (b >= t && r >= l) {
3049 return new Roo.lib.Region(t, r, b, l);
3054 union : function(region) {
3055 var t = Math.min(this.top, region.top);
3056 var r = Math.max(this.right, region.right);
3057 var b = Math.max(this.bottom, region.bottom);
3058 var l = Math.min(this.left, region.left);
3060 return new Roo.lib.Region(t, r, b, l);
3063 adjust : function(t, l, b, r) {
3072 Roo.lib.Region.getRegion = function(el) {
3073 var p = Roo.lib.Dom.getXY(el);
3076 var r = p[0] + el.offsetWidth;
3077 var b = p[1] + el.offsetHeight;
3080 return new Roo.lib.Region(t, r, b, l);
3083 * Portions of this file are based on pieces of Yahoo User Interface Library
3084 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3085 * YUI licensed under the BSD License:
3086 * http://developer.yahoo.net/yui/license.txt
3087 * <script type="text/javascript">
3090 //@@dep Roo.lib.Region
3093 Roo.lib.Point = function(x, y) {
3094 if (x instanceof Array) {
3098 this.x = this.right = this.left = this[0] = x;
3099 this.y = this.top = this.bottom = this[1] = y;
3102 Roo.lib.Point.prototype = new Roo.lib.Region();
3104 * Portions of this file are based on pieces of Yahoo User Interface Library
3105 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3106 * YUI licensed under the BSD License:
3107 * http://developer.yahoo.net/yui/license.txt
3108 * <script type="text/javascript">
3115 scroll : function(el, args, duration, easing, cb, scope) {
3116 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3119 motion : function(el, args, duration, easing, cb, scope) {
3120 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3123 color : function(el, args, duration, easing, cb, scope) {
3124 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3127 run : function(el, args, duration, easing, cb, scope, type) {
3128 type = type || Roo.lib.AnimBase;
3129 if (typeof easing == "string") {
3130 easing = Roo.lib.Easing[easing];
3132 var anim = new type(el, args, duration, easing);
3133 anim.animateX(function() {
3134 Roo.callback(cb, scope);
3140 * Portions of this file are based on pieces of Yahoo User Interface Library
3141 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3142 * YUI licensed under the BSD License:
3143 * http://developer.yahoo.net/yui/license.txt
3144 * <script type="text/javascript">
3152 if (!libFlyweight) {
3153 libFlyweight = new Roo.Element.Flyweight();
3155 libFlyweight.dom = el;
3156 return libFlyweight;
3159 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3163 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3165 this.init(el, attributes, duration, method);
3169 Roo.lib.AnimBase.fly = fly;
3173 Roo.lib.AnimBase.prototype = {
3175 toString: function() {
3176 var el = this.getEl();
3177 var id = el.id || el.tagName;
3178 return ("Anim " + id);
3182 noNegatives: /width|height|opacity|padding/i,
3183 offsetAttribute: /^((width|height)|(top|left))$/,
3184 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3185 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3189 doMethod: function(attr, start, end) {
3190 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3194 setAttribute: function(attr, val, unit) {
3195 if (this.patterns.noNegatives.test(attr)) {
3196 val = (val > 0) ? val : 0;
3199 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3203 getAttribute: function(attr) {
3204 var el = this.getEl();
3205 var val = fly(el).getStyle(attr);
3207 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3208 return parseFloat(val);
3211 var a = this.patterns.offsetAttribute.exec(attr) || [];
3212 var pos = !!( a[3] );
3213 var box = !!( a[2] );
3216 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3217 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3226 getDefaultUnit: function(attr) {
3227 if (this.patterns.defaultUnit.test(attr)) {
3234 animateX : function(callback, scope) {
3235 var f = function() {
3236 this.onComplete.removeListener(f);
3237 if (typeof callback == "function") {
3238 callback.call(scope || this, this);
3241 this.onComplete.addListener(f, this);
3246 setRuntimeAttribute: function(attr) {
3249 var attributes = this.attributes;
3251 this.runtimeAttributes[attr] = {};
3253 var isset = function(prop) {
3254 return (typeof prop !== 'undefined');
3257 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3261 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3264 if (isset(attributes[attr]['to'])) {
3265 end = attributes[attr]['to'];
3266 } else if (isset(attributes[attr]['by'])) {
3267 if (start.constructor == Array) {
3269 for (var i = 0, len = start.length; i < len; ++i) {
3270 end[i] = start[i] + attributes[attr]['by'][i];
3273 end = start + attributes[attr]['by'];
3277 this.runtimeAttributes[attr].start = start;
3278 this.runtimeAttributes[attr].end = end;
3281 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3285 init: function(el, attributes, duration, method) {
3287 var isAnimated = false;
3290 var startTime = null;
3293 var actualFrames = 0;
3296 el = Roo.getDom(el);
3299 this.attributes = attributes || {};
3302 this.duration = duration || 1;
3305 this.method = method || Roo.lib.Easing.easeNone;
3308 this.useSeconds = true;
3311 this.currentFrame = 0;
3314 this.totalFrames = Roo.lib.AnimMgr.fps;
3317 this.getEl = function() {
3322 this.isAnimated = function() {
3327 this.getStartTime = function() {
3331 this.runtimeAttributes = {};
3334 this.animate = function() {
3335 if (this.isAnimated()) {
3339 this.currentFrame = 0;
3341 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3343 Roo.lib.AnimMgr.registerElement(this);
3347 this.stop = function(finish) {
3349 this.currentFrame = this.totalFrames;
3350 this._onTween.fire();
3352 Roo.lib.AnimMgr.stop(this);
3355 var onStart = function() {
3356 this.onStart.fire();
3358 this.runtimeAttributes = {};
3359 for (var attr in this.attributes) {
3360 this.setRuntimeAttribute(attr);
3365 startTime = new Date();
3369 var onTween = function() {
3371 duration: new Date() - this.getStartTime(),
3372 currentFrame: this.currentFrame
3375 data.toString = function() {
3377 'duration: ' + data.duration +
3378 ', currentFrame: ' + data.currentFrame
3382 this.onTween.fire(data);
3384 var runtimeAttributes = this.runtimeAttributes;
3386 for (var attr in runtimeAttributes) {
3387 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3393 var onComplete = function() {
3394 var actual_duration = (new Date() - startTime) / 1000 ;
3397 duration: actual_duration,
3398 frames: actualFrames,
3399 fps: actualFrames / actual_duration
3402 data.toString = function() {
3404 'duration: ' + data.duration +
3405 ', frames: ' + data.frames +
3406 ', fps: ' + data.fps
3412 this.onComplete.fire(data);
3416 this._onStart = new Roo.util.Event(this);
3417 this.onStart = new Roo.util.Event(this);
3418 this.onTween = new Roo.util.Event(this);
3419 this._onTween = new Roo.util.Event(this);
3420 this.onComplete = new Roo.util.Event(this);
3421 this._onComplete = new Roo.util.Event(this);
3422 this._onStart.addListener(onStart);
3423 this._onTween.addListener(onTween);
3424 this._onComplete.addListener(onComplete);
3429 * Portions of this file are based on pieces of Yahoo User Interface Library
3430 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3431 * YUI licensed under the BSD License:
3432 * http://developer.yahoo.net/yui/license.txt
3433 * <script type="text/javascript">
3437 Roo.lib.AnimMgr = new function() {
3454 this.registerElement = function(tween) {
3455 queue[queue.length] = tween;
3457 tween._onStart.fire();
3462 this.unRegister = function(tween, index) {
3463 tween._onComplete.fire();
3464 index = index || getIndex(tween);
3466 queue.splice(index, 1);
3470 if (tweenCount <= 0) {
3476 this.start = function() {
3477 if (thread === null) {
3478 thread = setInterval(this.run, this.delay);
3483 this.stop = function(tween) {
3485 clearInterval(thread);
3487 for (var i = 0, len = queue.length; i < len; ++i) {
3488 if (queue[0].isAnimated()) {
3489 this.unRegister(queue[0], 0);
3498 this.unRegister(tween);
3503 this.run = function() {
3504 for (var i = 0, len = queue.length; i < len; ++i) {
3505 var tween = queue[i];
3506 if (!tween || !tween.isAnimated()) {
3510 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3512 tween.currentFrame += 1;
3514 if (tween.useSeconds) {
3515 correctFrame(tween);
3517 tween._onTween.fire();
3520 Roo.lib.AnimMgr.stop(tween, i);
3525 var getIndex = function(anim) {
3526 for (var i = 0, len = queue.length; i < len; ++i) {
3527 if (queue[i] == anim) {
3535 var correctFrame = function(tween) {
3536 var frames = tween.totalFrames;
3537 var frame = tween.currentFrame;
3538 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3539 var elapsed = (new Date() - tween.getStartTime());
3542 if (elapsed < tween.duration * 1000) {
3543 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3545 tweak = frames - (frame + 1);
3547 if (tweak > 0 && isFinite(tweak)) {
3548 if (tween.currentFrame + tweak >= frames) {
3549 tweak = frames - (frame + 1);
3552 tween.currentFrame += tweak;
3558 * Portions of this file are based on pieces of Yahoo User Interface Library
3559 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3560 * YUI licensed under the BSD License:
3561 * http://developer.yahoo.net/yui/license.txt
3562 * <script type="text/javascript">
3565 Roo.lib.Bezier = new function() {
3567 this.getPosition = function(points, t) {
3568 var n = points.length;
3571 for (var i = 0; i < n; ++i) {
3572 tmp[i] = [points[i][0], points[i][1]];
3575 for (var j = 1; j < n; ++j) {
3576 for (i = 0; i < n - j; ++i) {
3577 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3578 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3582 return [ tmp[0][0], tmp[0][1] ];
3586 * Portions of this file are based on pieces of Yahoo User Interface Library
3587 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3588 * YUI licensed under the BSD License:
3589 * http://developer.yahoo.net/yui/license.txt
3590 * <script type="text/javascript">
3595 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3596 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3599 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3601 var fly = Roo.lib.AnimBase.fly;
3603 var superclass = Y.ColorAnim.superclass;
3604 var proto = Y.ColorAnim.prototype;
3606 proto.toString = function() {
3607 var el = this.getEl();
3608 var id = el.id || el.tagName;
3609 return ("ColorAnim " + id);
3612 proto.patterns.color = /color$/i;
3613 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3614 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3615 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3616 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3619 proto.parseColor = function(s) {
3620 if (s.length == 3) {
3624 var c = this.patterns.hex.exec(s);
3625 if (c && c.length == 4) {
3626 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3629 c = this.patterns.rgb.exec(s);
3630 if (c && c.length == 4) {
3631 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3634 c = this.patterns.hex3.exec(s);
3635 if (c && c.length == 4) {
3636 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3641 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3642 proto.getAttribute = function(attr) {
3643 var el = this.getEl();
3644 if (this.patterns.color.test(attr)) {
3645 var val = fly(el).getStyle(attr);
3647 if (this.patterns.transparent.test(val)) {
3648 var parent = el.parentNode;
3649 val = fly(parent).getStyle(attr);
3651 while (parent && this.patterns.transparent.test(val)) {
3652 parent = parent.parentNode;
3653 val = fly(parent).getStyle(attr);
3654 if (parent.tagName.toUpperCase() == 'HTML') {
3660 val = superclass.getAttribute.call(this, attr);
3665 proto.getAttribute = function(attr) {
3666 var el = this.getEl();
3667 if (this.patterns.color.test(attr)) {
3668 var val = fly(el).getStyle(attr);
3670 if (this.patterns.transparent.test(val)) {
3671 var parent = el.parentNode;
3672 val = fly(parent).getStyle(attr);
3674 while (parent && this.patterns.transparent.test(val)) {
3675 parent = parent.parentNode;
3676 val = fly(parent).getStyle(attr);
3677 if (parent.tagName.toUpperCase() == 'HTML') {
3683 val = superclass.getAttribute.call(this, attr);
3689 proto.doMethod = function(attr, start, end) {
3692 if (this.patterns.color.test(attr)) {
3694 for (var i = 0, len = start.length; i < len; ++i) {
3695 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3698 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3701 val = superclass.doMethod.call(this, attr, start, end);
3707 proto.setRuntimeAttribute = function(attr) {
3708 superclass.setRuntimeAttribute.call(this, attr);
3710 if (this.patterns.color.test(attr)) {
3711 var attributes = this.attributes;
3712 var start = this.parseColor(this.runtimeAttributes[attr].start);
3713 var end = this.parseColor(this.runtimeAttributes[attr].end);
3715 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3716 end = this.parseColor(attributes[attr].by);
3718 for (var i = 0, len = start.length; i < len; ++i) {
3719 end[i] = start[i] + end[i];
3723 this.runtimeAttributes[attr].start = start;
3724 this.runtimeAttributes[attr].end = end;
3730 * Portions of this file are based on pieces of Yahoo User Interface Library
3731 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732 * YUI licensed under the BSD License:
3733 * http://developer.yahoo.net/yui/license.txt
3734 * <script type="text/javascript">
3740 easeNone: function (t, b, c, d) {
3741 return c * t / d + b;
3745 easeIn: function (t, b, c, d) {
3746 return c * (t /= d) * t + b;
3750 easeOut: function (t, b, c, d) {
3751 return -c * (t /= d) * (t - 2) + b;
3755 easeBoth: function (t, b, c, d) {
3756 if ((t /= d / 2) < 1) {
3757 return c / 2 * t * t + b;
3760 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3764 easeInStrong: function (t, b, c, d) {
3765 return c * (t /= d) * t * t * t + b;
3769 easeOutStrong: function (t, b, c, d) {
3770 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3774 easeBothStrong: function (t, b, c, d) {
3775 if ((t /= d / 2) < 1) {
3776 return c / 2 * t * t * t * t + b;
3779 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3784 elasticIn: function (t, b, c, d, a, p) {
3788 if ((t /= d) == 1) {
3795 if (!a || a < Math.abs(c)) {
3800 var s = p / (2 * Math.PI) * Math.asin(c / a);
3803 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3807 elasticOut: function (t, b, c, d, a, p) {
3811 if ((t /= d) == 1) {
3818 if (!a || a < Math.abs(c)) {
3823 var s = p / (2 * Math.PI) * Math.asin(c / a);
3826 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3830 elasticBoth: function (t, b, c, d, a, p) {
3835 if ((t /= d / 2) == 2) {
3843 if (!a || a < Math.abs(c)) {
3848 var s = p / (2 * Math.PI) * Math.asin(c / a);
3852 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3853 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3855 return a * Math.pow(2, -10 * (t -= 1)) *
3856 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3861 backIn: function (t, b, c, d, s) {
3862 if (typeof s == 'undefined') {
3865 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3869 backOut: function (t, b, c, d, s) {
3870 if (typeof s == 'undefined') {
3873 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3877 backBoth: function (t, b, c, d, s) {
3878 if (typeof s == 'undefined') {
3882 if ((t /= d / 2 ) < 1) {
3883 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3885 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3889 bounceIn: function (t, b, c, d) {
3890 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3894 bounceOut: function (t, b, c, d) {
3895 if ((t /= d) < (1 / 2.75)) {
3896 return c * (7.5625 * t * t) + b;
3897 } else if (t < (2 / 2.75)) {
3898 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3899 } else if (t < (2.5 / 2.75)) {
3900 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3902 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3906 bounceBoth: function (t, b, c, d) {
3908 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3910 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3913 * Portions of this file are based on pieces of Yahoo User Interface Library
3914 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3915 * YUI licensed under the BSD License:
3916 * http://developer.yahoo.net/yui/license.txt
3917 * <script type="text/javascript">
3921 Roo.lib.Motion = function(el, attributes, duration, method) {
3923 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3927 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3931 var superclass = Y.Motion.superclass;
3932 var proto = Y.Motion.prototype;
3934 proto.toString = function() {
3935 var el = this.getEl();
3936 var id = el.id || el.tagName;
3937 return ("Motion " + id);
3940 proto.patterns.points = /^points$/i;
3942 proto.setAttribute = function(attr, val, unit) {
3943 if (this.patterns.points.test(attr)) {
3944 unit = unit || 'px';
3945 superclass.setAttribute.call(this, 'left', val[0], unit);
3946 superclass.setAttribute.call(this, 'top', val[1], unit);
3948 superclass.setAttribute.call(this, attr, val, unit);
3952 proto.getAttribute = function(attr) {
3953 if (this.patterns.points.test(attr)) {
3955 superclass.getAttribute.call(this, 'left'),
3956 superclass.getAttribute.call(this, 'top')
3959 val = superclass.getAttribute.call(this, attr);
3965 proto.doMethod = function(attr, start, end) {
3968 if (this.patterns.points.test(attr)) {
3969 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3970 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3972 val = superclass.doMethod.call(this, attr, start, end);
3977 proto.setRuntimeAttribute = function(attr) {
3978 if (this.patterns.points.test(attr)) {
3979 var el = this.getEl();
3980 var attributes = this.attributes;
3982 var control = attributes['points']['control'] || [];
3986 if (control.length > 0 && !(control[0] instanceof Array)) {
3987 control = [control];
3990 for (i = 0,len = control.length; i < len; ++i) {
3991 tmp[i] = control[i];
3996 Roo.fly(el).position();
3998 if (isset(attributes['points']['from'])) {
3999 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4002 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4005 start = this.getAttribute('points');
4008 if (isset(attributes['points']['to'])) {
4009 end = translateValues.call(this, attributes['points']['to'], start);
4011 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4012 for (i = 0,len = control.length; i < len; ++i) {
4013 control[i] = translateValues.call(this, control[i], start);
4017 } else if (isset(attributes['points']['by'])) {
4018 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4020 for (i = 0,len = control.length; i < len; ++i) {
4021 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4025 this.runtimeAttributes[attr] = [start];
4027 if (control.length > 0) {
4028 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4031 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4034 superclass.setRuntimeAttribute.call(this, attr);
4038 var translateValues = function(val, start) {
4039 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4040 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4045 var isset = function(prop) {
4046 return (typeof prop !== 'undefined');
4050 * Portions of this file are based on pieces of Yahoo User Interface Library
4051 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4052 * YUI licensed under the BSD License:
4053 * http://developer.yahoo.net/yui/license.txt
4054 * <script type="text/javascript">
4058 Roo.lib.Scroll = function(el, attributes, duration, method) {
4060 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4064 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4068 var superclass = Y.Scroll.superclass;
4069 var proto = Y.Scroll.prototype;
4071 proto.toString = function() {
4072 var el = this.getEl();
4073 var id = el.id || el.tagName;
4074 return ("Scroll " + id);
4077 proto.doMethod = function(attr, start, end) {
4080 if (attr == 'scroll') {
4082 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4083 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4087 val = superclass.doMethod.call(this, attr, start, end);
4092 proto.getAttribute = function(attr) {
4094 var el = this.getEl();
4096 if (attr == 'scroll') {
4097 val = [ el.scrollLeft, el.scrollTop ];
4099 val = superclass.getAttribute.call(this, attr);
4105 proto.setAttribute = function(attr, val, unit) {
4106 var el = this.getEl();
4108 if (attr == 'scroll') {
4109 el.scrollLeft = val[0];
4110 el.scrollTop = val[1];
4112 superclass.setAttribute.call(this, attr, val, unit);
4118 * Ext JS Library 1.1.1
4119 * Copyright(c) 2006-2007, Ext JS, LLC.
4121 * Originally Released Under LGPL - original licence link has changed is not relivant.
4124 * <script type="text/javascript">
4128 // nasty IE9 hack - what a pile of crap that is..
4130 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4131 Range.prototype.createContextualFragment = function (html) {
4132 var doc = window.document;
4133 var container = doc.createElement("div");
4134 container.innerHTML = html;
4135 var frag = doc.createDocumentFragment(), n;
4136 while ((n = container.firstChild)) {
4137 frag.appendChild(n);
4144 * @class Roo.DomHelper
4145 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4146 * 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>.
4149 Roo.DomHelper = function(){
4150 var tempTableEl = null;
4151 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4152 var tableRe = /^table|tbody|tr|td$/i;
4154 // build as innerHTML where available
4156 var createHtml = function(o){
4157 if(typeof o == 'string'){
4166 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4167 if(attr == "style"){
4169 if(typeof s == "function"){
4172 if(typeof s == "string"){
4173 b += ' style="' + s + '"';
4174 }else if(typeof s == "object"){
4177 if(typeof s[key] != "function"){
4178 b += key + ":" + s[key] + ";";
4185 b += ' class="' + o["cls"] + '"';
4186 }else if(attr == "htmlFor"){
4187 b += ' for="' + o["htmlFor"] + '"';
4189 b += " " + attr + '="' + o[attr] + '"';
4193 if(emptyTags.test(o.tag)){
4197 var cn = o.children || o.cn;
4199 //http://bugs.kde.org/show_bug.cgi?id=71506
4200 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4201 for(var i = 0, len = cn.length; i < len; i++) {
4202 b += createHtml(cn[i], b);
4205 b += createHtml(cn, b);
4211 b += "</" + o.tag + ">";
4218 var createDom = function(o, parentNode){
4220 // defininition craeted..
4222 if (o.ns && o.ns != 'html') {
4224 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4225 xmlns[o.ns] = o.xmlns;
4228 if (typeof(xmlns[o.ns]) == 'undefined') {
4229 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4235 if (typeof(o) == 'string') {
4236 return parentNode.appendChild(document.createTextNode(o));
4238 o.tag = o.tag || div;
4239 if (o.ns && Roo.isIE) {
4241 o.tag = o.ns + ':' + o.tag;
4244 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4245 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4248 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4249 attr == "style" || typeof o[attr] == "function") { continue; }
4251 if(attr=="cls" && Roo.isIE){
4252 el.className = o["cls"];
4254 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4260 Roo.DomHelper.applyStyles(el, o.style);
4261 var cn = o.children || o.cn;
4263 //http://bugs.kde.org/show_bug.cgi?id=71506
4264 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4265 for(var i = 0, len = cn.length; i < len; i++) {
4266 createDom(cn[i], el);
4273 el.innerHTML = o.html;
4276 parentNode.appendChild(el);
4281 var ieTable = function(depth, s, h, e){
4282 tempTableEl.innerHTML = [s, h, e].join('');
4283 var i = -1, el = tempTableEl;
4290 // kill repeat to save bytes
4294 tbe = '</tbody>'+te,
4300 * Nasty code for IE's broken table implementation
4302 var insertIntoTable = function(tag, where, el, html){
4304 tempTableEl = document.createElement('div');
4309 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4312 if(where == 'beforebegin'){
4316 before = el.nextSibling;
4319 node = ieTable(4, trs, html, tre);
4321 else if(tag == 'tr'){
4322 if(where == 'beforebegin'){
4325 node = ieTable(3, tbs, html, tbe);
4326 } else if(where == 'afterend'){
4327 before = el.nextSibling;
4329 node = ieTable(3, tbs, html, tbe);
4330 } else{ // INTO a TR
4331 if(where == 'afterbegin'){
4332 before = el.firstChild;
4334 node = ieTable(4, trs, html, tre);
4336 } else if(tag == 'tbody'){
4337 if(where == 'beforebegin'){
4340 node = ieTable(2, ts, html, te);
4341 } else if(where == 'afterend'){
4342 before = el.nextSibling;
4344 node = ieTable(2, ts, html, te);
4346 if(where == 'afterbegin'){
4347 before = el.firstChild;
4349 node = ieTable(3, tbs, html, tbe);
4352 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4355 if(where == 'afterbegin'){
4356 before = el.firstChild;
4358 node = ieTable(2, ts, html, te);
4360 el.insertBefore(node, before);
4365 /** True to force the use of DOM instead of html fragments @type Boolean */
4369 * Returns the markup for the passed Element(s) config
4370 * @param {Object} o The Dom object spec (and children)
4373 markup : function(o){
4374 return createHtml(o);
4378 * Applies a style specification to an element
4379 * @param {String/HTMLElement} el The element to apply styles to
4380 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4381 * a function which returns such a specification.
4383 applyStyles : function(el, styles){
4386 if(typeof styles == "string"){
4387 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4389 while ((matches = re.exec(styles)) != null){
4390 el.setStyle(matches[1], matches[2]);
4392 }else if (typeof styles == "object"){
4393 for (var style in styles){
4394 el.setStyle(style, styles[style]);
4396 }else if (typeof styles == "function"){
4397 Roo.DomHelper.applyStyles(el, styles.call());
4403 * Inserts an HTML fragment into the Dom
4404 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4405 * @param {HTMLElement} el The context element
4406 * @param {String} html The HTML fragmenet
4407 * @return {HTMLElement} The new node
4409 insertHtml : function(where, el, html){
4410 where = where.toLowerCase();
4411 if(el.insertAdjacentHTML){
4412 if(tableRe.test(el.tagName)){
4414 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4420 el.insertAdjacentHTML('BeforeBegin', html);
4421 return el.previousSibling;
4423 el.insertAdjacentHTML('AfterBegin', html);
4424 return el.firstChild;
4426 el.insertAdjacentHTML('BeforeEnd', html);
4427 return el.lastChild;
4429 el.insertAdjacentHTML('AfterEnd', html);
4430 return el.nextSibling;
4432 throw 'Illegal insertion point -> "' + where + '"';
4434 var range = el.ownerDocument.createRange();
4438 range.setStartBefore(el);
4439 frag = range.createContextualFragment(html);
4440 el.parentNode.insertBefore(frag, el);
4441 return el.previousSibling;
4444 range.setStartBefore(el.firstChild);
4445 frag = range.createContextualFragment(html);
4446 el.insertBefore(frag, el.firstChild);
4447 return el.firstChild;
4449 el.innerHTML = html;
4450 return el.firstChild;
4454 range.setStartAfter(el.lastChild);
4455 frag = range.createContextualFragment(html);
4456 el.appendChild(frag);
4457 return el.lastChild;
4459 el.innerHTML = html;
4460 return el.lastChild;
4463 range.setStartAfter(el);
4464 frag = range.createContextualFragment(html);
4465 el.parentNode.insertBefore(frag, el.nextSibling);
4466 return el.nextSibling;
4468 throw 'Illegal insertion point -> "' + where + '"';
4472 * Creates new Dom element(s) and inserts them before el
4473 * @param {String/HTMLElement/Element} el The context element
4474 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476 * @return {HTMLElement/Roo.Element} The new node
4478 insertBefore : function(el, o, returnElement){
4479 return this.doInsert(el, o, returnElement, "beforeBegin");
4483 * Creates new Dom element(s) and inserts them after el
4484 * @param {String/HTMLElement/Element} el The context element
4485 * @param {Object} o The Dom object spec (and children)
4486 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4487 * @return {HTMLElement/Roo.Element} The new node
4489 insertAfter : function(el, o, returnElement){
4490 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4494 * Creates new Dom element(s) and inserts them as the first child of el
4495 * @param {String/HTMLElement/Element} el The context element
4496 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4497 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4498 * @return {HTMLElement/Roo.Element} The new node
4500 insertFirst : function(el, o, returnElement){
4501 return this.doInsert(el, o, returnElement, "afterBegin");
4505 doInsert : function(el, o, returnElement, pos, sibling){
4506 el = Roo.getDom(el);
4508 if(this.useDom || o.ns){
4509 newNode = createDom(o, null);
4510 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4512 var html = createHtml(o);
4513 newNode = this.insertHtml(pos, el, html);
4515 return returnElement ? Roo.get(newNode, true) : newNode;
4519 * Creates new Dom element(s) and appends them to el
4520 * @param {String/HTMLElement/Element} el The context element
4521 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4522 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4523 * @return {HTMLElement/Roo.Element} The new node
4525 append : function(el, o, returnElement){
4526 el = Roo.getDom(el);
4528 if(this.useDom || o.ns){
4529 newNode = createDom(o, null);
4530 el.appendChild(newNode);
4532 var html = createHtml(o);
4533 newNode = this.insertHtml("beforeEnd", el, html);
4535 return returnElement ? Roo.get(newNode, true) : newNode;
4539 * Creates new Dom element(s) and overwrites the contents of el with them
4540 * @param {String/HTMLElement/Element} el The context element
4541 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4542 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4543 * @return {HTMLElement/Roo.Element} The new node
4545 overwrite : function(el, o, returnElement){
4546 el = Roo.getDom(el);
4549 while (el.childNodes.length) {
4550 el.removeChild(el.firstChild);
4554 el.innerHTML = createHtml(o);
4557 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4561 * Creates a new Roo.DomHelper.Template from the Dom object spec
4562 * @param {Object} o The Dom object spec (and children)
4563 * @return {Roo.DomHelper.Template} The new template
4565 createTemplate : function(o){
4566 var html = createHtml(o);
4567 return new Roo.Template(html);
4573 * Ext JS Library 1.1.1
4574 * Copyright(c) 2006-2007, Ext JS, LLC.
4576 * Originally Released Under LGPL - original licence link has changed is not relivant.
4579 * <script type="text/javascript">
4583 * @class Roo.Template
4584 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4585 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4588 var t = new Roo.Template({
4589 html : '<div name="{id}">' +
4590 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4592 myformat: function (value, allValues) {
4593 return 'XX' + value;
4596 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4598 * For more information see this blog post with examples:
4599 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4600 - Create Elements using DOM, HTML fragments and Templates</a>.
4602 * @param {Object} cfg - Configuration object.
4604 Roo.Template = function(cfg){
4606 if(cfg instanceof Array){
4608 }else if(arguments.length > 1){
4609 cfg = Array.prototype.join.call(arguments, "");
4613 if (typeof(cfg) == 'object') {
4624 Roo.Template.prototype = {
4627 * @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..
4628 * it should be fixed so that template is observable...
4632 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4636 * Returns an HTML fragment of this template with the specified values applied.
4637 * @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'})
4638 * @return {String} The HTML fragment
4640 applyTemplate : function(values){
4644 return this.compiled(values);
4646 var useF = this.disableFormats !== true;
4647 var fm = Roo.util.Format, tpl = this;
4648 var fn = function(m, name, format, args){
4650 if(format.substr(0, 5) == "this."){
4651 return tpl.call(format.substr(5), values[name], values);
4654 // quoted values are required for strings in compiled templates,
4655 // but for non compiled we need to strip them
4656 // quoted reversed for jsmin
4657 var re = /^\s*['"](.*)["']\s*$/;
4658 args = args.split(',');
4659 for(var i = 0, len = args.length; i < len; i++){
4660 args[i] = args[i].replace(re, "$1");
4662 args = [values[name]].concat(args);
4664 args = [values[name]];
4666 return fm[format].apply(fm, args);
4669 return values[name] !== undefined ? values[name] : "";
4672 return this.html.replace(this.re, fn);
4690 this.loading = true;
4691 this.compiled = false;
4693 var cx = new Roo.data.Connection();
4697 success : function (response) {
4699 _t.html = response.responseText;
4703 failure : function(response) {
4704 Roo.log("Template failed to load from " + _t.url);
4711 * Sets the HTML used as the template and optionally compiles it.
4712 * @param {String} html
4713 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4714 * @return {Roo.Template} this
4716 set : function(html, compile){
4718 this.compiled = null;
4726 * True to disable format functions (defaults to false)
4729 disableFormats : false,
4732 * The regular expression used to match template variables
4736 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4739 * Compiles the template into an internal function, eliminating the RegEx overhead.
4740 * @return {Roo.Template} this
4742 compile : function(){
4743 var fm = Roo.util.Format;
4744 var useF = this.disableFormats !== true;
4745 var sep = Roo.isGecko ? "+" : ",";
4746 var fn = function(m, name, format, args){
4748 args = args ? ',' + args : "";
4749 if(format.substr(0, 5) != "this."){
4750 format = "fm." + format + '(';
4752 format = 'this.call("'+ format.substr(5) + '", ';
4756 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4758 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4761 // branched to use + in gecko and [].join() in others
4763 body = "this.compiled = function(values){ return '" +
4764 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4767 body = ["this.compiled = function(values){ return ['"];
4768 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4769 body.push("'].join('');};");
4770 body = body.join('');
4780 // private function used to call members
4781 call : function(fnName, value, allValues){
4782 return this[fnName](value, allValues);
4786 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4787 * @param {String/HTMLElement/Roo.Element} el The context element
4788 * @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'})
4789 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790 * @return {HTMLElement/Roo.Element} The new node or Element
4792 insertFirst: function(el, values, returnElement){
4793 return this.doInsert('afterBegin', el, values, returnElement);
4797 * Applies the supplied values to the template and inserts the new node(s) before el.
4798 * @param {String/HTMLElement/Roo.Element} el The context element
4799 * @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'})
4800 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801 * @return {HTMLElement/Roo.Element} The new node or Element
4803 insertBefore: function(el, values, returnElement){
4804 return this.doInsert('beforeBegin', el, values, returnElement);
4808 * Applies the supplied values to the template and inserts the new node(s) after el.
4809 * @param {String/HTMLElement/Roo.Element} el The context element
4810 * @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'})
4811 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4812 * @return {HTMLElement/Roo.Element} The new node or Element
4814 insertAfter : function(el, values, returnElement){
4815 return this.doInsert('afterEnd', el, values, returnElement);
4819 * Applies the supplied values to the template and appends the new node(s) to el.
4820 * @param {String/HTMLElement/Roo.Element} el The context element
4821 * @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'})
4822 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823 * @return {HTMLElement/Roo.Element} The new node or Element
4825 append : function(el, values, returnElement){
4826 return this.doInsert('beforeEnd', el, values, returnElement);
4829 doInsert : function(where, el, values, returnEl){
4830 el = Roo.getDom(el);
4831 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4832 return returnEl ? Roo.get(newNode, true) : newNode;
4836 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4837 * @param {String/HTMLElement/Roo.Element} el The context element
4838 * @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'})
4839 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4840 * @return {HTMLElement/Roo.Element} The new node or Element
4842 overwrite : function(el, values, returnElement){
4843 el = Roo.getDom(el);
4844 el.innerHTML = this.applyTemplate(values);
4845 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4849 * Alias for {@link #applyTemplate}
4852 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4855 Roo.DomHelper.Template = Roo.Template;
4858 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4859 * @param {String/HTMLElement} el A DOM element or its id
4860 * @returns {Roo.Template} The created template
4863 Roo.Template.from = function(el){
4864 el = Roo.getDom(el);
4865 return new Roo.Template(el.value || el.innerHTML);
4868 * Ext JS Library 1.1.1
4869 * Copyright(c) 2006-2007, Ext JS, LLC.
4871 * Originally Released Under LGPL - original licence link has changed is not relivant.
4874 * <script type="text/javascript">
4879 * This is code is also distributed under MIT license for use
4880 * with jQuery and prototype JavaScript libraries.
4883 * @class Roo.DomQuery
4884 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).
4886 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>
4889 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.
4891 <h4>Element Selectors:</h4>
4893 <li> <b>*</b> any element</li>
4894 <li> <b>E</b> an element with the tag E</li>
4895 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4896 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4897 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4898 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4900 <h4>Attribute Selectors:</h4>
4901 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4903 <li> <b>E[foo]</b> has an attribute "foo"</li>
4904 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4905 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4906 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4907 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4908 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4909 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4911 <h4>Pseudo Classes:</h4>
4913 <li> <b>E:first-child</b> E is the first child of its parent</li>
4914 <li> <b>E:last-child</b> E is the last child of its parent</li>
4915 <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>
4916 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4917 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4918 <li> <b>E:only-child</b> E is the only child of its parent</li>
4919 <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>
4920 <li> <b>E:first</b> the first E in the resultset</li>
4921 <li> <b>E:last</b> the last E in the resultset</li>
4922 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4923 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4924 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4925 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4926 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4927 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4928 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4929 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4930 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4932 <h4>CSS Value Selectors:</h4>
4934 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4935 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4936 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4937 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4938 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4939 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4943 Roo.DomQuery = function(){
4944 var cache = {}, simpleCache = {}, valueCache = {};
4945 var nonSpace = /\S/;
4946 var trimRe = /^\s+|\s+$/g;
4947 var tplRe = /\{(\d+)\}/g;
4948 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4949 var tagTokenRe = /^(#)?([\w-\*]+)/;
4950 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4952 function child(p, index){
4954 var n = p.firstChild;
4956 if(n.nodeType == 1){
4967 while((n = n.nextSibling) && n.nodeType != 1);
4972 while((n = n.previousSibling) && n.nodeType != 1);
4976 function children(d){
4977 var n = d.firstChild, ni = -1;
4979 var nx = n.nextSibling;
4980 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4990 function byClassName(c, a, v){
4994 var r = [], ri = -1, cn;
4995 for(var i = 0, ci; ci = c[i]; i++){
4996 if((' '+ci.className+' ').indexOf(v) != -1){
5003 function attrValue(n, attr){
5004 if(!n.tagName && typeof n.length != "undefined"){
5013 if(attr == "class" || attr == "className"){
5016 return n.getAttribute(attr) || n[attr];
5020 function getNodes(ns, mode, tagName){
5021 var result = [], ri = -1, cs;
5025 tagName = tagName || "*";
5026 if(typeof ns.getElementsByTagName != "undefined"){
5030 for(var i = 0, ni; ni = ns[i]; i++){
5031 cs = ni.getElementsByTagName(tagName);
5032 for(var j = 0, ci; ci = cs[j]; j++){
5036 }else if(mode == "/" || mode == ">"){
5037 var utag = tagName.toUpperCase();
5038 for(var i = 0, ni, cn; ni = ns[i]; i++){
5039 cn = ni.children || ni.childNodes;
5040 for(var j = 0, cj; cj = cn[j]; j++){
5041 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5046 }else if(mode == "+"){
5047 var utag = tagName.toUpperCase();
5048 for(var i = 0, n; n = ns[i]; i++){
5049 while((n = n.nextSibling) && n.nodeType != 1);
5050 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5054 }else if(mode == "~"){
5055 for(var i = 0, n; n = ns[i]; i++){
5056 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5065 function concat(a, b){
5069 for(var i = 0, l = b.length; i < l; i++){
5075 function byTag(cs, tagName){
5076 if(cs.tagName || cs == document){
5082 var r = [], ri = -1;
5083 tagName = tagName.toLowerCase();
5084 for(var i = 0, ci; ci = cs[i]; i++){
5085 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5092 function byId(cs, attr, id){
5093 if(cs.tagName || cs == document){
5099 var r = [], ri = -1;
5100 for(var i = 0,ci; ci = cs[i]; i++){
5101 if(ci && ci.id == id){
5109 function byAttribute(cs, attr, value, op, custom){
5110 var r = [], ri = -1, st = custom=="{";
5111 var f = Roo.DomQuery.operators[op];
5112 for(var i = 0, ci; ci = cs[i]; i++){
5115 a = Roo.DomQuery.getStyle(ci, attr);
5117 else if(attr == "class" || attr == "className"){
5119 }else if(attr == "for"){
5121 }else if(attr == "href"){
5122 a = ci.getAttribute("href", 2);
5124 a = ci.getAttribute(attr);
5126 if((f && f(a, value)) || (!f && a)){
5133 function byPseudo(cs, name, value){
5134 return Roo.DomQuery.pseudos[name](cs, value);
5137 // This is for IE MSXML which does not support expandos.
5138 // IE runs the same speed using setAttribute, however FF slows way down
5139 // and Safari completely fails so they need to continue to use expandos.
5140 var isIE = window.ActiveXObject ? true : false;
5142 // this eval is stop the compressor from
5143 // renaming the variable to something shorter
5145 /** eval:var:batch */
5150 function nodupIEXml(cs){
5152 cs[0].setAttribute("_nodup", d);
5154 for(var i = 1, len = cs.length; i < len; i++){
5156 if(!c.getAttribute("_nodup") != d){
5157 c.setAttribute("_nodup", d);
5161 for(var i = 0, len = cs.length; i < len; i++){
5162 cs[i].removeAttribute("_nodup");
5171 var len = cs.length, c, i, r = cs, cj, ri = -1;
5172 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5175 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5176 return nodupIEXml(cs);
5180 for(i = 1; c = cs[i]; i++){
5185 for(var j = 0; j < i; j++){
5188 for(j = i+1; cj = cs[j]; j++){
5200 function quickDiffIEXml(c1, c2){
5202 for(var i = 0, len = c1.length; i < len; i++){
5203 c1[i].setAttribute("_qdiff", d);
5206 for(var i = 0, len = c2.length; i < len; i++){
5207 if(c2[i].getAttribute("_qdiff") != d){
5208 r[r.length] = c2[i];
5211 for(var i = 0, len = c1.length; i < len; i++){
5212 c1[i].removeAttribute("_qdiff");
5217 function quickDiff(c1, c2){
5218 var len1 = c1.length;
5222 if(isIE && c1[0].selectSingleNode){
5223 return quickDiffIEXml(c1, c2);
5226 for(var i = 0; i < len1; i++){
5230 for(var i = 0, len = c2.length; i < len; i++){
5231 if(c2[i]._qdiff != d){
5232 r[r.length] = c2[i];
5238 function quickId(ns, mode, root, id){
5240 var d = root.ownerDocument || root;
5241 return d.getElementById(id);
5243 ns = getNodes(ns, mode, "*");
5244 return byId(ns, null, id);
5248 getStyle : function(el, name){
5249 return Roo.fly(el).getStyle(name);
5252 * Compiles a selector/xpath query into a reusable function. The returned function
5253 * takes one parameter "root" (optional), which is the context node from where the query should start.
5254 * @param {String} selector The selector/xpath query
5255 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5256 * @return {Function}
5258 compile : function(path, type){
5259 type = type || "select";
5261 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5262 var q = path, mode, lq;
5263 var tk = Roo.DomQuery.matchers;
5264 var tklen = tk.length;
5267 // accept leading mode switch
5268 var lmode = q.match(modeRe);
5269 if(lmode && lmode[1]){
5270 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5271 q = q.replace(lmode[1], "");
5273 // strip leading slashes
5274 while(path.substr(0, 1)=="/"){
5275 path = path.substr(1);
5278 while(q && lq != q){
5280 var tm = q.match(tagTokenRe);
5281 if(type == "select"){
5284 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5286 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5288 q = q.replace(tm[0], "");
5289 }else if(q.substr(0, 1) != '@'){
5290 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5295 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5297 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5299 q = q.replace(tm[0], "");
5302 while(!(mm = q.match(modeRe))){
5303 var matched = false;
5304 for(var j = 0; j < tklen; j++){
5306 var m = q.match(t.re);
5308 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5311 q = q.replace(m[0], "");
5316 // prevent infinite loop on bad selector
5318 throw 'Error parsing selector, parsing failed at "' + q + '"';
5322 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5323 q = q.replace(mm[1], "");
5326 fn[fn.length] = "return nodup(n);\n}";
5329 * list of variables that need from compression as they are used by eval.
5339 * eval:var:byClassName
5341 * eval:var:byAttribute
5342 * eval:var:attrValue
5350 * Selects a group of elements.
5351 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5352 * @param {Node} root (optional) The start of the query (defaults to document).
5355 select : function(path, root, type){
5356 if(!root || root == document){
5359 if(typeof root == "string"){
5360 root = document.getElementById(root);
5362 var paths = path.split(",");
5364 for(var i = 0, len = paths.length; i < len; i++){
5365 var p = paths[i].replace(trimRe, "");
5367 cache[p] = Roo.DomQuery.compile(p);
5369 throw p + " is not a valid selector";
5372 var result = cache[p](root);
5373 if(result && result != document){
5374 results = results.concat(result);
5377 if(paths.length > 1){
5378 return nodup(results);
5384 * Selects a single element.
5385 * @param {String} selector The selector/xpath query
5386 * @param {Node} root (optional) The start of the query (defaults to document).
5389 selectNode : function(path, root){
5390 return Roo.DomQuery.select(path, root)[0];
5394 * Selects the value of a node, optionally replacing null with the defaultValue.
5395 * @param {String} selector The selector/xpath query
5396 * @param {Node} root (optional) The start of the query (defaults to document).
5397 * @param {String} defaultValue
5399 selectValue : function(path, root, defaultValue){
5400 path = path.replace(trimRe, "");
5401 if(!valueCache[path]){
5402 valueCache[path] = Roo.DomQuery.compile(path, "select");
5404 var n = valueCache[path](root);
5405 n = n[0] ? n[0] : n;
5406 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5407 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5411 * Selects the value of a node, parsing integers and floats.
5412 * @param {String} selector The selector/xpath query
5413 * @param {Node} root (optional) The start of the query (defaults to document).
5414 * @param {Number} defaultValue
5417 selectNumber : function(path, root, defaultValue){
5418 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5419 return parseFloat(v);
5423 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5424 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5425 * @param {String} selector The simple selector to test
5428 is : function(el, ss){
5429 if(typeof el == "string"){
5430 el = document.getElementById(el);
5432 var isArray = (el instanceof Array);
5433 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5434 return isArray ? (result.length == el.length) : (result.length > 0);
5438 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5439 * @param {Array} el An array of elements to filter
5440 * @param {String} selector The simple selector to test
5441 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5442 * the selector instead of the ones that match
5445 filter : function(els, ss, nonMatches){
5446 ss = ss.replace(trimRe, "");
5447 if(!simpleCache[ss]){
5448 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5450 var result = simpleCache[ss](els);
5451 return nonMatches ? quickDiff(result, els) : result;
5455 * Collection of matching regular expressions and code snippets.
5459 select: 'n = byClassName(n, null, " {1} ");'
5461 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5462 select: 'n = byPseudo(n, "{1}", "{2}");'
5464 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5465 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5468 select: 'n = byId(n, null, "{1}");'
5471 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5476 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5477 * 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, > <.
5480 "=" : function(a, v){
5483 "!=" : function(a, v){
5486 "^=" : function(a, v){
5487 return a && a.substr(0, v.length) == v;
5489 "$=" : function(a, v){
5490 return a && a.substr(a.length-v.length) == v;
5492 "*=" : function(a, v){
5493 return a && a.indexOf(v) !== -1;
5495 "%=" : function(a, v){
5496 return (a % v) == 0;
5498 "|=" : function(a, v){
5499 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5501 "~=" : function(a, v){
5502 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5507 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5508 * and the argument (if any) supplied in the selector.
5511 "first-child" : function(c){
5512 var r = [], ri = -1, n;
5513 for(var i = 0, ci; ci = n = c[i]; i++){
5514 while((n = n.previousSibling) && n.nodeType != 1);
5522 "last-child" : function(c){
5523 var r = [], ri = -1, n;
5524 for(var i = 0, ci; ci = n = c[i]; i++){
5525 while((n = n.nextSibling) && n.nodeType != 1);
5533 "nth-child" : function(c, a) {
5534 var r = [], ri = -1;
5535 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5536 var f = (m[1] || 1) - 0, l = m[2] - 0;
5537 for(var i = 0, n; n = c[i]; i++){
5538 var pn = n.parentNode;
5539 if (batch != pn._batch) {
5541 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5542 if(cn.nodeType == 1){
5549 if (l == 0 || n.nodeIndex == l){
5552 } else if ((n.nodeIndex + l) % f == 0){
5560 "only-child" : function(c){
5561 var r = [], ri = -1;;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 if(!prev(ci) && !next(ci)){
5570 "empty" : function(c){
5571 var r = [], ri = -1;
5572 for(var i = 0, ci; ci = c[i]; i++){
5573 var cns = ci.childNodes, j = 0, cn, empty = true;
5576 if(cn.nodeType == 1 || cn.nodeType == 3){
5588 "contains" : function(c, v){
5589 var r = [], ri = -1;
5590 for(var i = 0, ci; ci = c[i]; i++){
5591 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5598 "nodeValue" : function(c, v){
5599 var r = [], ri = -1;
5600 for(var i = 0, ci; ci = c[i]; i++){
5601 if(ci.firstChild && ci.firstChild.nodeValue == v){
5608 "checked" : function(c){
5609 var r = [], ri = -1;
5610 for(var i = 0, ci; ci = c[i]; i++){
5611 if(ci.checked == true){
5618 "not" : function(c, ss){
5619 return Roo.DomQuery.filter(c, ss, true);
5622 "odd" : function(c){
5623 return this["nth-child"](c, "odd");
5626 "even" : function(c){
5627 return this["nth-child"](c, "even");
5630 "nth" : function(c, a){
5631 return c[a-1] || [];
5634 "first" : function(c){
5638 "last" : function(c){
5639 return c[c.length-1] || [];
5642 "has" : function(c, ss){
5643 var s = Roo.DomQuery.select;
5644 var r = [], ri = -1;
5645 for(var i = 0, ci; ci = c[i]; i++){
5646 if(s(ss, ci).length > 0){
5653 "next" : function(c, ss){
5654 var is = Roo.DomQuery.is;
5655 var r = [], ri = -1;
5656 for(var i = 0, ci; ci = c[i]; i++){
5665 "prev" : function(c, ss){
5666 var is = Roo.DomQuery.is;
5667 var r = [], ri = -1;
5668 for(var i = 0, ci; ci = c[i]; i++){
5681 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5682 * @param {String} path The selector/xpath query
5683 * @param {Node} root (optional) The start of the query (defaults to document).
5688 Roo.query = Roo.DomQuery.select;
5691 * Ext JS Library 1.1.1
5692 * Copyright(c) 2006-2007, Ext JS, LLC.
5694 * Originally Released Under LGPL - original licence link has changed is not relivant.
5697 * <script type="text/javascript">
5701 * @class Roo.util.Observable
5702 * Base class that provides a common interface for publishing events. Subclasses are expected to
5703 * to have a property "events" with all the events defined.<br>
5706 Employee = function(name){
5713 Roo.extend(Employee, Roo.util.Observable);
5715 * @param {Object} config properties to use (incuding events / listeners)
5718 Roo.util.Observable = function(cfg){
5721 this.addEvents(cfg.events || {});
5723 delete cfg.events; // make sure
5726 Roo.apply(this, cfg);
5729 this.on(this.listeners);
5730 delete this.listeners;
5733 Roo.util.Observable.prototype = {
5735 * @cfg {Object} listeners list of events and functions to call for this object,
5739 'click' : function(e) {
5749 * Fires the specified event with the passed parameters (minus the event name).
5750 * @param {String} eventName
5751 * @param {Object...} args Variable number of parameters are passed to handlers
5752 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5754 fireEvent : function(){
5755 var ce = this.events[arguments[0].toLowerCase()];
5756 if(typeof ce == "object"){
5757 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5764 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5767 * Appends an event handler to this component
5768 * @param {String} eventName The type of event to listen for
5769 * @param {Function} handler The method the event invokes
5770 * @param {Object} scope (optional) The scope in which to execute the handler
5771 * function. The handler function's "this" context.
5772 * @param {Object} options (optional) An object containing handler configuration
5773 * properties. This may contain any of the following properties:<ul>
5774 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5775 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5776 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5777 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5778 * by the specified number of milliseconds. If the event fires again within that time, the original
5779 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5782 * <b>Combining Options</b><br>
5783 * Using the options argument, it is possible to combine different types of listeners:<br>
5785 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5787 el.on('click', this.onClick, this, {
5794 * <b>Attaching multiple handlers in 1 call</b><br>
5795 * The method also allows for a single argument to be passed which is a config object containing properties
5796 * which specify multiple handlers.
5805 fn: this.onMouseOver,
5809 fn: this.onMouseOut,
5815 * Or a shorthand syntax which passes the same scope object to all handlers:
5818 'click': this.onClick,
5819 'mouseover': this.onMouseOver,
5820 'mouseout': this.onMouseOut,
5825 addListener : function(eventName, fn, scope, o){
5826 if(typeof eventName == "object"){
5829 if(this.filterOptRe.test(e)){
5832 if(typeof o[e] == "function"){
5834 this.addListener(e, o[e], o.scope, o);
5836 // individual options
5837 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5842 o = (!o || typeof o == "boolean") ? {} : o;
5843 eventName = eventName.toLowerCase();
5844 var ce = this.events[eventName] || true;
5845 if(typeof ce == "boolean"){
5846 ce = new Roo.util.Event(this, eventName);
5847 this.events[eventName] = ce;
5849 ce.addListener(fn, scope, o);
5853 * Removes a listener
5854 * @param {String} eventName The type of event to listen for
5855 * @param {Function} handler The handler to remove
5856 * @param {Object} scope (optional) The scope (this object) for the handler
5858 removeListener : function(eventName, fn, scope){
5859 var ce = this.events[eventName.toLowerCase()];
5860 if(typeof ce == "object"){
5861 ce.removeListener(fn, scope);
5866 * Removes all listeners for this object
5868 purgeListeners : function(){
5869 for(var evt in this.events){
5870 if(typeof this.events[evt] == "object"){
5871 this.events[evt].clearListeners();
5876 relayEvents : function(o, events){
5877 var createHandler = function(ename){
5879 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5882 for(var i = 0, len = events.length; i < len; i++){
5883 var ename = events[i];
5884 if(!this.events[ename]){ this.events[ename] = true; };
5885 o.on(ename, createHandler(ename), this);
5890 * Used to define events on this Observable
5891 * @param {Object} object The object with the events defined
5893 addEvents : function(o){
5897 Roo.applyIf(this.events, o);
5901 * Checks to see if this object has any listeners for a specified event
5902 * @param {String} eventName The name of the event to check for
5903 * @return {Boolean} True if the event is being listened for, else false
5905 hasListener : function(eventName){
5906 var e = this.events[eventName];
5907 return typeof e == "object" && e.listeners.length > 0;
5911 * Appends an event handler to this element (shorthand for addListener)
5912 * @param {String} eventName The type of event to listen for
5913 * @param {Function} handler The method the event invokes
5914 * @param {Object} scope (optional) The scope in which to execute the handler
5915 * function. The handler function's "this" context.
5916 * @param {Object} options (optional)
5919 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5921 * Removes a listener (shorthand for removeListener)
5922 * @param {String} eventName The type of event to listen for
5923 * @param {Function} handler The handler to remove
5924 * @param {Object} scope (optional) The scope (this object) for the handler
5927 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5930 * Starts capture on the specified Observable. All events will be passed
5931 * to the supplied function with the event name + standard signature of the event
5932 * <b>before</b> the event is fired. If the supplied function returns false,
5933 * the event will not fire.
5934 * @param {Observable} o The Observable to capture
5935 * @param {Function} fn The function to call
5936 * @param {Object} scope (optional) The scope (this object) for the fn
5939 Roo.util.Observable.capture = function(o, fn, scope){
5940 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5944 * Removes <b>all</b> added captures from the Observable.
5945 * @param {Observable} o The Observable to release
5948 Roo.util.Observable.releaseCapture = function(o){
5949 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5954 var createBuffered = function(h, o, scope){
5955 var task = new Roo.util.DelayedTask();
5957 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5961 var createSingle = function(h, e, fn, scope){
5963 e.removeListener(fn, scope);
5964 return h.apply(scope, arguments);
5968 var createDelayed = function(h, o, scope){
5970 var args = Array.prototype.slice.call(arguments, 0);
5971 setTimeout(function(){
5972 h.apply(scope, args);
5977 Roo.util.Event = function(obj, name){
5980 this.listeners = [];
5983 Roo.util.Event.prototype = {
5984 addListener : function(fn, scope, options){
5985 var o = options || {};
5986 scope = scope || this.obj;
5987 if(!this.isListening(fn, scope)){
5988 var l = {fn: fn, scope: scope, options: o};
5991 h = createDelayed(h, o, scope);
5994 h = createSingle(h, this, fn, scope);
5997 h = createBuffered(h, o, scope);
6000 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6001 this.listeners.push(l);
6003 this.listeners = this.listeners.slice(0);
6004 this.listeners.push(l);
6009 findListener : function(fn, scope){
6010 scope = scope || this.obj;
6011 var ls = this.listeners;
6012 for(var i = 0, len = ls.length; i < len; i++){
6014 if(l.fn == fn && l.scope == scope){
6021 isListening : function(fn, scope){
6022 return this.findListener(fn, scope) != -1;
6025 removeListener : function(fn, scope){
6027 if((index = this.findListener(fn, scope)) != -1){
6029 this.listeners.splice(index, 1);
6031 this.listeners = this.listeners.slice(0);
6032 this.listeners.splice(index, 1);
6039 clearListeners : function(){
6040 this.listeners = [];
6044 var ls = this.listeners, scope, len = ls.length;
6047 var args = Array.prototype.slice.call(arguments, 0);
6048 for(var i = 0; i < len; i++){
6050 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6051 this.firing = false;
6055 this.firing = false;
6062 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6069 * @class Roo.Document
6070 * @extends Roo.util.Observable
6071 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6073 * @param {Object} config the methods and properties of the 'base' class for the application.
6075 * Generic Page handler - implement this to start your app..
6078 * MyProject = new Roo.Document({
6080 'load' : true // your events..
6083 'ready' : function() {
6084 // fired on Roo.onReady()
6089 Roo.Document = function(cfg) {
6094 Roo.util.Observable.call(this,cfg);
6098 Roo.onReady(function() {
6099 _this.fireEvent('ready');
6105 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6107 * Ext JS Library 1.1.1
6108 * Copyright(c) 2006-2007, Ext JS, LLC.
6110 * Originally Released Under LGPL - original licence link has changed is not relivant.
6113 * <script type="text/javascript">
6117 * @class Roo.EventManager
6118 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6119 * several useful events directly.
6120 * See {@link Roo.EventObject} for more details on normalized event objects.
6123 Roo.EventManager = function(){
6124 var docReadyEvent, docReadyProcId, docReadyState = false;
6125 var resizeEvent, resizeTask, textEvent, textSize;
6126 var E = Roo.lib.Event;
6127 var D = Roo.lib.Dom;
6132 var fireDocReady = function(){
6134 docReadyState = true;
6137 clearInterval(docReadyProcId);
6139 if(Roo.isGecko || Roo.isOpera) {
6140 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6143 var defer = document.getElementById("ie-deferred-loader");
6145 defer.onreadystatechange = null;
6146 defer.parentNode.removeChild(defer);
6150 docReadyEvent.fire();
6151 docReadyEvent.clearListeners();
6156 var initDocReady = function(){
6157 docReadyEvent = new Roo.util.Event();
6158 if(Roo.isGecko || Roo.isOpera) {
6159 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6161 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6162 var defer = document.getElementById("ie-deferred-loader");
6163 defer.onreadystatechange = function(){
6164 if(this.readyState == "complete"){
6168 }else if(Roo.isSafari){
6169 docReadyProcId = setInterval(function(){
6170 var rs = document.readyState;
6171 if(rs == "complete") {
6176 // no matter what, make sure it fires on load
6177 E.on(window, "load", fireDocReady);
6180 var createBuffered = function(h, o){
6181 var task = new Roo.util.DelayedTask(h);
6183 // create new event object impl so new events don't wipe out properties
6184 e = new Roo.EventObjectImpl(e);
6185 task.delay(o.buffer, h, null, [e]);
6189 var createSingle = function(h, el, ename, fn){
6191 Roo.EventManager.removeListener(el, ename, fn);
6196 var createDelayed = function(h, o){
6198 // create new event object impl so new events don't wipe out properties
6199 e = new Roo.EventObjectImpl(e);
6200 setTimeout(function(){
6205 var transitionEndVal = false;
6207 var transitionEnd = function()
6209 if (transitionEndVal) {
6210 return transitionEndVal;
6212 var el = document.createElement('div');
6214 var transEndEventNames = {
6215 WebkitTransition : 'webkitTransitionEnd',
6216 MozTransition : 'transitionend',
6217 OTransition : 'oTransitionEnd otransitionend',
6218 transition : 'transitionend'
6221 for (var name in transEndEventNames) {
6222 if (el.style[name] !== undefined) {
6223 transitionEndVal = transEndEventNames[name];
6224 return transitionEndVal ;
6230 var listen = function(element, ename, opt, fn, scope){
6231 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6232 fn = fn || o.fn; scope = scope || o.scope;
6233 var el = Roo.getDom(element);
6237 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6240 if (ename == 'transitionend') {
6241 ename = transitionEnd();
6243 var h = function(e){
6244 e = Roo.EventObject.setEvent(e);
6247 t = e.getTarget(o.delegate, el);
6254 if(o.stopEvent === true){
6257 if(o.preventDefault === true){
6260 if(o.stopPropagation === true){
6261 e.stopPropagation();
6264 if(o.normalized === false){
6268 fn.call(scope || el, e, t, o);
6271 h = createDelayed(h, o);
6274 h = createSingle(h, el, ename, fn);
6277 h = createBuffered(h, o);
6279 fn._handlers = fn._handlers || [];
6282 fn._handlers.push([Roo.id(el), ename, h]);
6287 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6288 el.addEventListener("DOMMouseScroll", h, false);
6289 E.on(window, 'unload', function(){
6290 el.removeEventListener("DOMMouseScroll", h, false);
6293 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6294 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6299 var stopListening = function(el, ename, fn){
6300 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6302 for(var i = 0, len = hds.length; i < len; i++){
6304 if(h[0] == id && h[1] == ename){
6311 E.un(el, ename, hd);
6312 el = Roo.getDom(el);
6313 if(ename == "mousewheel" && el.addEventListener){
6314 el.removeEventListener("DOMMouseScroll", hd, false);
6316 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6317 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6321 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6328 * @scope Roo.EventManager
6333 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6334 * object with a Roo.EventObject
6335 * @param {Function} fn The method the event invokes
6336 * @param {Object} scope An object that becomes the scope of the handler
6337 * @param {boolean} override If true, the obj passed in becomes
6338 * the execution scope of the listener
6339 * @return {Function} The wrapped function
6342 wrap : function(fn, scope, override){
6344 Roo.EventObject.setEvent(e);
6345 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6350 * Appends an event handler to an element (shorthand for addListener)
6351 * @param {String/HTMLElement} element The html element or id to assign the
6352 * @param {String} eventName The type of event to listen for
6353 * @param {Function} handler The method the event invokes
6354 * @param {Object} scope (optional) The scope in which to execute the handler
6355 * function. The handler function's "this" context.
6356 * @param {Object} options (optional) An object containing handler configuration
6357 * properties. This may contain any of the following properties:<ul>
6358 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6359 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6360 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6361 * <li>preventDefault {Boolean} True to prevent the default action</li>
6362 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6363 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6364 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6365 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6366 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6367 * by the specified number of milliseconds. If the event fires again within that time, the original
6368 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6371 * <b>Combining Options</b><br>
6372 * Using the options argument, it is possible to combine different types of listeners:<br>
6374 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6376 el.on('click', this.onClick, this, {
6383 * <b>Attaching multiple handlers in 1 call</b><br>
6384 * The method also allows for a single argument to be passed which is a config object containing properties
6385 * which specify multiple handlers.
6395 fn: this.onMouseOver
6404 * Or a shorthand syntax:<br>
6407 'click' : this.onClick,
6408 'mouseover' : this.onMouseOver,
6409 'mouseout' : this.onMouseOut
6413 addListener : function(element, eventName, fn, scope, options){
6414 if(typeof eventName == "object"){
6420 if(typeof o[e] == "function"){
6422 listen(element, e, o, o[e], o.scope);
6424 // individual options
6425 listen(element, e, o[e]);
6430 return listen(element, eventName, options, fn, scope);
6434 * Removes an event handler
6436 * @param {String/HTMLElement} element The id or html element to remove the
6438 * @param {String} eventName The type of event
6439 * @param {Function} fn
6440 * @return {Boolean} True if a listener was actually removed
6442 removeListener : function(element, eventName, fn){
6443 return stopListening(element, eventName, fn);
6447 * Fires when the document is ready (before onload and before images are loaded). Can be
6448 * accessed shorthanded Roo.onReady().
6449 * @param {Function} fn The method the event invokes
6450 * @param {Object} scope An object that becomes the scope of the handler
6451 * @param {boolean} options
6453 onDocumentReady : function(fn, scope, options){
6454 if(docReadyState){ // if it already fired
6455 docReadyEvent.addListener(fn, scope, options);
6456 docReadyEvent.fire();
6457 docReadyEvent.clearListeners();
6463 docReadyEvent.addListener(fn, scope, options);
6467 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6468 * @param {Function} fn The method the event invokes
6469 * @param {Object} scope An object that becomes the scope of the handler
6470 * @param {boolean} options
6472 onWindowResize : function(fn, scope, options){
6474 resizeEvent = new Roo.util.Event();
6475 resizeTask = new Roo.util.DelayedTask(function(){
6476 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6478 E.on(window, "resize", function(){
6480 resizeTask.delay(50);
6482 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6486 resizeEvent.addListener(fn, scope, options);
6490 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6491 * @param {Function} fn The method the event invokes
6492 * @param {Object} scope An object that becomes the scope of the handler
6493 * @param {boolean} options
6495 onTextResize : function(fn, scope, options){
6497 textEvent = new Roo.util.Event();
6498 var textEl = new Roo.Element(document.createElement('div'));
6499 textEl.dom.className = 'x-text-resize';
6500 textEl.dom.innerHTML = 'X';
6501 textEl.appendTo(document.body);
6502 textSize = textEl.dom.offsetHeight;
6503 setInterval(function(){
6504 if(textEl.dom.offsetHeight != textSize){
6505 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6507 }, this.textResizeInterval);
6509 textEvent.addListener(fn, scope, options);
6513 * Removes the passed window resize listener.
6514 * @param {Function} fn The method the event invokes
6515 * @param {Object} scope The scope of handler
6517 removeResizeListener : function(fn, scope){
6519 resizeEvent.removeListener(fn, scope);
6524 fireResize : function(){
6526 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6530 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6534 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6536 textResizeInterval : 50
6541 * @scopeAlias pub=Roo.EventManager
6545 * Appends an event handler to an element (shorthand for addListener)
6546 * @param {String/HTMLElement} element The html element or id to assign the
6547 * @param {String} eventName The type of event to listen for
6548 * @param {Function} handler The method the event invokes
6549 * @param {Object} scope (optional) The scope in which to execute the handler
6550 * function. The handler function's "this" context.
6551 * @param {Object} options (optional) An object containing handler configuration
6552 * properties. This may contain any of the following properties:<ul>
6553 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6554 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6555 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6556 * <li>preventDefault {Boolean} True to prevent the default action</li>
6557 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6558 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6559 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6560 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6561 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6562 * by the specified number of milliseconds. If the event fires again within that time, the original
6563 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6566 * <b>Combining Options</b><br>
6567 * Using the options argument, it is possible to combine different types of listeners:<br>
6569 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6571 el.on('click', this.onClick, this, {
6578 * <b>Attaching multiple handlers in 1 call</b><br>
6579 * The method also allows for a single argument to be passed which is a config object containing properties
6580 * which specify multiple handlers.
6590 fn: this.onMouseOver
6599 * Or a shorthand syntax:<br>
6602 'click' : this.onClick,
6603 'mouseover' : this.onMouseOver,
6604 'mouseout' : this.onMouseOut
6608 pub.on = pub.addListener;
6609 pub.un = pub.removeListener;
6611 pub.stoppedMouseDownEvent = new Roo.util.Event();
6615 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6616 * @param {Function} fn The method the event invokes
6617 * @param {Object} scope An object that becomes the scope of the handler
6618 * @param {boolean} override If true, the obj passed in becomes
6619 * the execution scope of the listener
6623 Roo.onReady = Roo.EventManager.onDocumentReady;
6625 Roo.onReady(function(){
6626 var bd = Roo.get(document.body);
6631 : Roo.isGecko ? "roo-gecko"
6632 : Roo.isOpera ? "roo-opera"
6633 : Roo.isSafari ? "roo-safari" : ""];
6636 cls.push("roo-mac");
6639 cls.push("roo-linux");
6642 cls.push("roo-ios");
6645 cls.push("roo-touch");
6647 if(Roo.isBorderBox){
6648 cls.push('roo-border-box');
6650 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6651 var p = bd.dom.parentNode;
6653 p.className += ' roo-strict';
6656 bd.addClass(cls.join(' '));
6660 * @class Roo.EventObject
6661 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6662 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6665 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6667 var target = e.getTarget();
6670 var myDiv = Roo.get("myDiv");
6671 myDiv.on("click", handleClick);
6673 Roo.EventManager.on("myDiv", 'click', handleClick);
6674 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6678 Roo.EventObject = function(){
6680 var E = Roo.lib.Event;
6682 // safari keypress events for special keys return bad keycodes
6685 63235 : 39, // right
6688 63276 : 33, // page up
6689 63277 : 34, // page down
6690 63272 : 46, // delete
6695 // normalize button clicks
6696 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6697 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6699 Roo.EventObjectImpl = function(e){
6701 this.setEvent(e.browserEvent || e);
6704 Roo.EventObjectImpl.prototype = {
6706 * Used to fix doc tools.
6707 * @scope Roo.EventObject.prototype
6713 /** The normal browser event */
6714 browserEvent : null,
6715 /** The button pressed in a mouse event */
6717 /** True if the shift key was down during the event */
6719 /** True if the control key was down during the event */
6721 /** True if the alt key was down during the event */
6780 setEvent : function(e){
6781 if(e == this || (e && e.browserEvent)){ // already wrapped
6784 this.browserEvent = e;
6786 // normalize buttons
6787 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6788 if(e.type == 'click' && this.button == -1){
6792 this.shiftKey = e.shiftKey;
6793 // mac metaKey behaves like ctrlKey
6794 this.ctrlKey = e.ctrlKey || e.metaKey;
6795 this.altKey = e.altKey;
6796 // in getKey these will be normalized for the mac
6797 this.keyCode = e.keyCode;
6798 // keyup warnings on firefox.
6799 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6800 // cache the target for the delayed and or buffered events
6801 this.target = E.getTarget(e);
6803 this.xy = E.getXY(e);
6806 this.shiftKey = false;
6807 this.ctrlKey = false;
6808 this.altKey = false;
6818 * Stop the event (preventDefault and stopPropagation)
6820 stopEvent : function(){
6821 if(this.browserEvent){
6822 if(this.browserEvent.type == 'mousedown'){
6823 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6825 E.stopEvent(this.browserEvent);
6830 * Prevents the browsers default handling of the event.
6832 preventDefault : function(){
6833 if(this.browserEvent){
6834 E.preventDefault(this.browserEvent);
6839 isNavKeyPress : function(){
6840 var k = this.keyCode;
6841 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6842 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6845 isSpecialKey : function(){
6846 var k = this.keyCode;
6847 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6848 (k == 16) || (k == 17) ||
6849 (k >= 18 && k <= 20) ||
6850 (k >= 33 && k <= 35) ||
6851 (k >= 36 && k <= 39) ||
6852 (k >= 44 && k <= 45);
6855 * Cancels bubbling of the event.
6857 stopPropagation : function(){
6858 if(this.browserEvent){
6859 if(this.type == 'mousedown'){
6860 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6862 E.stopPropagation(this.browserEvent);
6867 * Gets the key code for the event.
6870 getCharCode : function(){
6871 return this.charCode || this.keyCode;
6875 * Returns a normalized keyCode for the event.
6876 * @return {Number} The key code
6878 getKey : function(){
6879 var k = this.keyCode || this.charCode;
6880 return Roo.isSafari ? (safariKeys[k] || k) : k;
6884 * Gets the x coordinate of the event.
6887 getPageX : function(){
6892 * Gets the y coordinate of the event.
6895 getPageY : function(){
6900 * Gets the time of the event.
6903 getTime : function(){
6904 if(this.browserEvent){
6905 return E.getTime(this.browserEvent);
6911 * Gets the page coordinates of the event.
6912 * @return {Array} The xy values like [x, y]
6919 * Gets the target for the event.
6920 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6921 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6922 search as a number or element (defaults to 10 || document.body)
6923 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6924 * @return {HTMLelement}
6926 getTarget : function(selector, maxDepth, returnEl){
6927 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6930 * Gets the related target.
6931 * @return {HTMLElement}
6933 getRelatedTarget : function(){
6934 if(this.browserEvent){
6935 return E.getRelatedTarget(this.browserEvent);
6941 * Normalizes mouse wheel delta across browsers
6942 * @return {Number} The delta
6944 getWheelDelta : function(){
6945 var e = this.browserEvent;
6947 if(e.wheelDelta){ /* IE/Opera. */
6948 delta = e.wheelDelta/120;
6949 }else if(e.detail){ /* Mozilla case. */
6950 delta = -e.detail/3;
6956 * Returns true if the control, meta, shift or alt key was pressed during this event.
6959 hasModifier : function(){
6960 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6964 * Returns true if the target of this event equals el or is a child of el
6965 * @param {String/HTMLElement/Element} el
6966 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6969 within : function(el, related){
6970 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6971 return t && Roo.fly(el).contains(t);
6974 getPoint : function(){
6975 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6979 return new Roo.EventObjectImpl();
6984 * Ext JS Library 1.1.1
6985 * Copyright(c) 2006-2007, Ext JS, LLC.
6987 * Originally Released Under LGPL - original licence link has changed is not relivant.
6990 * <script type="text/javascript">
6994 // was in Composite Element!??!?!
6997 var D = Roo.lib.Dom;
6998 var E = Roo.lib.Event;
6999 var A = Roo.lib.Anim;
7001 // local style camelizing for speed
7003 var camelRe = /(-[a-z])/gi;
7004 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7005 var view = document.defaultView;
7008 * @class Roo.Element
7009 * Represents an Element in the DOM.<br><br>
7012 var el = Roo.get("my-div");
7015 var el = getEl("my-div");
7017 // or with a DOM element
7018 var el = Roo.get(myDivElement);
7020 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7021 * each call instead of constructing a new one.<br><br>
7022 * <b>Animations</b><br />
7023 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7024 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7026 Option Default Description
7027 --------- -------- ---------------------------------------------
7028 duration .35 The duration of the animation in seconds
7029 easing easeOut The YUI easing method
7030 callback none A function to execute when the anim completes
7031 scope this The scope (this) of the callback function
7033 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7034 * manipulate the animation. Here's an example:
7036 var el = Roo.get("my-div");
7041 // default animation
7042 el.setWidth(100, true);
7044 // animation with some options set
7051 // using the "anim" property to get the Anim object
7057 el.setWidth(100, opt);
7059 if(opt.anim.isAnimated()){
7063 * <b> Composite (Collections of) Elements</b><br />
7064 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7065 * @constructor Create a new Element directly.
7066 * @param {String/HTMLElement} element
7067 * @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).
7069 Roo.Element = function(element, forceNew){
7070 var dom = typeof element == "string" ?
7071 document.getElementById(element) : element;
7072 if(!dom){ // invalid id/element
7076 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7077 return Roo.Element.cache[id];
7087 * The DOM element ID
7090 this.id = id || Roo.id(dom);
7093 var El = Roo.Element;
7097 * The element's default display mode (defaults to "")
7100 originalDisplay : "",
7104 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7110 * Sets the element's visibility mode. When setVisible() is called it
7111 * will use this to determine whether to set the visibility or the display property.
7112 * @param visMode Element.VISIBILITY or Element.DISPLAY
7113 * @return {Roo.Element} this
7115 setVisibilityMode : function(visMode){
7116 this.visibilityMode = visMode;
7120 * Convenience method for setVisibilityMode(Element.DISPLAY)
7121 * @param {String} display (optional) What to set display to when visible
7122 * @return {Roo.Element} this
7124 enableDisplayMode : function(display){
7125 this.setVisibilityMode(El.DISPLAY);
7126 if(typeof display != "undefined") { this.originalDisplay = display; }
7131 * 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)
7132 * @param {String} selector The simple selector to test
7133 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7134 search as a number or element (defaults to 10 || document.body)
7135 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7136 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7138 findParent : function(simpleSelector, maxDepth, returnEl){
7139 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7140 maxDepth = maxDepth || 50;
7141 if(typeof maxDepth != "number"){
7142 stopEl = Roo.getDom(maxDepth);
7145 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7146 if(dq.is(p, simpleSelector)){
7147 return returnEl ? Roo.get(p) : p;
7157 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7158 * @param {String} selector The simple selector to test
7159 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7160 search as a number or element (defaults to 10 || document.body)
7161 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7162 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7164 findParentNode : function(simpleSelector, maxDepth, returnEl){
7165 var p = Roo.fly(this.dom.parentNode, '_internal');
7166 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7170 * Looks at the scrollable parent element
7172 findScrollableParent : function()
7174 var overflowRegex = /(auto|scroll)/;
7176 if(this.getStyle('position') === 'fixed'){
7177 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7180 var excludeStaticParent = this.getStyle('position') === "absolute";
7182 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7184 if (excludeStaticParent && parent.getStyle('position') === "static") {
7188 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7192 if(parent.dom.nodeName.toLowerCase() == 'body'){
7193 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7197 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7201 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7202 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7203 * @param {String} selector The simple selector to test
7204 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7205 search as a number or element (defaults to 10 || document.body)
7206 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7208 up : function(simpleSelector, maxDepth){
7209 return this.findParentNode(simpleSelector, maxDepth, true);
7215 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7216 * @param {String} selector The simple selector to test
7217 * @return {Boolean} True if this element matches the selector, else false
7219 is : function(simpleSelector){
7220 return Roo.DomQuery.is(this.dom, simpleSelector);
7224 * Perform animation on this element.
7225 * @param {Object} args The YUI animation control args
7226 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7227 * @param {Function} onComplete (optional) Function to call when animation completes
7228 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7229 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7230 * @return {Roo.Element} this
7232 animate : function(args, duration, onComplete, easing, animType){
7233 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7238 * @private Internal animation call
7240 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7241 animType = animType || 'run';
7243 var anim = Roo.lib.Anim[animType](
7245 (opt.duration || defaultDur) || .35,
7246 (opt.easing || defaultEase) || 'easeOut',
7248 Roo.callback(cb, this);
7249 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7257 // private legacy anim prep
7258 preanim : function(a, i){
7259 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7263 * Removes worthless text nodes
7264 * @param {Boolean} forceReclean (optional) By default the element
7265 * keeps track if it has been cleaned already so
7266 * you can call this over and over. However, if you update the element and
7267 * need to force a reclean, you can pass true.
7269 clean : function(forceReclean){
7270 if(this.isCleaned && forceReclean !== true){
7274 var d = this.dom, n = d.firstChild, ni = -1;
7276 var nx = n.nextSibling;
7277 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7284 this.isCleaned = true;
7289 calcOffsetsTo : function(el){
7292 var restorePos = false;
7293 if(el.getStyle('position') == 'static'){
7294 el.position('relative');
7299 while(op && op != d && op.tagName != 'HTML'){
7302 op = op.offsetParent;
7305 el.position('static');
7311 * Scrolls this element into view within the passed container.
7312 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7313 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7314 * @return {Roo.Element} this
7316 scrollIntoView : function(container, hscroll){
7317 var c = Roo.getDom(container) || document.body;
7320 var o = this.calcOffsetsTo(c),
7323 b = t+el.offsetHeight,
7324 r = l+el.offsetWidth;
7326 var ch = c.clientHeight;
7327 var ct = parseInt(c.scrollTop, 10);
7328 var cl = parseInt(c.scrollLeft, 10);
7330 var cr = cl + c.clientWidth;
7338 if(hscroll !== false){
7342 c.scrollLeft = r-c.clientWidth;
7349 scrollChildIntoView : function(child, hscroll){
7350 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7354 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7355 * the new height may not be available immediately.
7356 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7357 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7358 * @param {Function} onComplete (optional) Function to call when animation completes
7359 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7360 * @return {Roo.Element} this
7362 autoHeight : function(animate, duration, onComplete, easing){
7363 var oldHeight = this.getHeight();
7365 this.setHeight(1); // force clipping
7366 setTimeout(function(){
7367 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7369 this.setHeight(height);
7371 if(typeof onComplete == "function"){
7375 this.setHeight(oldHeight); // restore original height
7376 this.setHeight(height, animate, duration, function(){
7378 if(typeof onComplete == "function") { onComplete(); }
7379 }.createDelegate(this), easing);
7381 }.createDelegate(this), 0);
7386 * Returns true if this element is an ancestor of the passed element
7387 * @param {HTMLElement/String} el The element to check
7388 * @return {Boolean} True if this element is an ancestor of el, else false
7390 contains : function(el){
7391 if(!el){return false;}
7392 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7396 * Checks whether the element is currently visible using both visibility and display properties.
7397 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7398 * @return {Boolean} True if the element is currently visible, else false
7400 isVisible : function(deep) {
7401 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7402 if(deep !== true || !vis){
7405 var p = this.dom.parentNode;
7406 while(p && p.tagName.toLowerCase() != "body"){
7407 if(!Roo.fly(p, '_isVisible').isVisible()){
7416 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7417 * @param {String} selector The CSS selector
7418 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7419 * @return {CompositeElement/CompositeElementLite} The composite element
7421 select : function(selector, unique){
7422 return El.select(selector, unique, this.dom);
7426 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7427 * @param {String} selector The CSS selector
7428 * @return {Array} An array of the matched nodes
7430 query : function(selector, unique){
7431 return Roo.DomQuery.select(selector, this.dom);
7435 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7436 * @param {String} selector The CSS selector
7437 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7438 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7440 child : function(selector, returnDom){
7441 var n = Roo.DomQuery.selectNode(selector, this.dom);
7442 return returnDom ? n : Roo.get(n);
7446 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7447 * @param {String} selector The CSS selector
7448 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7449 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7451 down : function(selector, returnDom){
7452 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7453 return returnDom ? n : Roo.get(n);
7457 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7458 * @param {String} group The group the DD object is member of
7459 * @param {Object} config The DD config object
7460 * @param {Object} overrides An object containing methods to override/implement on the DD object
7461 * @return {Roo.dd.DD} The DD object
7463 initDD : function(group, config, overrides){
7464 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7465 return Roo.apply(dd, overrides);
7469 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7470 * @param {String} group The group the DDProxy object is member of
7471 * @param {Object} config The DDProxy config object
7472 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7473 * @return {Roo.dd.DDProxy} The DDProxy object
7475 initDDProxy : function(group, config, overrides){
7476 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7477 return Roo.apply(dd, overrides);
7481 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7482 * @param {String} group The group the DDTarget object is member of
7483 * @param {Object} config The DDTarget config object
7484 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7485 * @return {Roo.dd.DDTarget} The DDTarget object
7487 initDDTarget : function(group, config, overrides){
7488 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7489 return Roo.apply(dd, overrides);
7493 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7494 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7495 * @param {Boolean} visible Whether the element is visible
7496 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7497 * @return {Roo.Element} this
7499 setVisible : function(visible, animate){
7501 if(this.visibilityMode == El.DISPLAY){
7502 this.setDisplayed(visible);
7505 this.dom.style.visibility = visible ? "visible" : "hidden";
7508 // closure for composites
7510 var visMode = this.visibilityMode;
7512 this.setOpacity(.01);
7513 this.setVisible(true);
7515 this.anim({opacity: { to: (visible?1:0) }},
7516 this.preanim(arguments, 1),
7517 null, .35, 'easeIn', function(){
7519 if(visMode == El.DISPLAY){
7520 dom.style.display = "none";
7522 dom.style.visibility = "hidden";
7524 Roo.get(dom).setOpacity(1);
7532 * Returns true if display is not "none"
7535 isDisplayed : function() {
7536 return this.getStyle("display") != "none";
7540 * Toggles the element's visibility or display, depending on visibility mode.
7541 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7542 * @return {Roo.Element} this
7544 toggle : function(animate){
7545 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7550 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7551 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7552 * @return {Roo.Element} this
7554 setDisplayed : function(value) {
7555 if(typeof value == "boolean"){
7556 value = value ? this.originalDisplay : "none";
7558 this.setStyle("display", value);
7563 * Tries to focus the element. Any exceptions are caught and ignored.
7564 * @return {Roo.Element} this
7566 focus : function() {
7574 * Tries to blur the element. Any exceptions are caught and ignored.
7575 * @return {Roo.Element} this
7585 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7586 * @param {String/Array} className The CSS class to add, or an array of classes
7587 * @return {Roo.Element} this
7589 addClass : function(className){
7590 if(className instanceof Array){
7591 for(var i = 0, len = className.length; i < len; i++) {
7592 this.addClass(className[i]);
7595 if(className && !this.hasClass(className)){
7596 this.dom.className = this.dom.className + " " + className;
7603 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7604 * @param {String/Array} className The CSS class to add, or an array of classes
7605 * @return {Roo.Element} this
7607 radioClass : function(className){
7608 var siblings = this.dom.parentNode.childNodes;
7609 for(var i = 0; i < siblings.length; i++) {
7610 var s = siblings[i];
7611 if(s.nodeType == 1){
7612 Roo.get(s).removeClass(className);
7615 this.addClass(className);
7620 * Removes one or more CSS classes from the element.
7621 * @param {String/Array} className The CSS class to remove, or an array of classes
7622 * @return {Roo.Element} this
7624 removeClass : function(className){
7625 if(!className || !this.dom.className){
7628 if(className instanceof Array){
7629 for(var i = 0, len = className.length; i < len; i++) {
7630 this.removeClass(className[i]);
7633 if(this.hasClass(className)){
7634 var re = this.classReCache[className];
7636 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7637 this.classReCache[className] = re;
7639 this.dom.className =
7640 this.dom.className.replace(re, " ");
7650 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7651 * @param {String} className The CSS class to toggle
7652 * @return {Roo.Element} this
7654 toggleClass : function(className){
7655 if(this.hasClass(className)){
7656 this.removeClass(className);
7658 this.addClass(className);
7664 * Checks if the specified CSS class exists on this element's DOM node.
7665 * @param {String} className The CSS class to check for
7666 * @return {Boolean} True if the class exists, else false
7668 hasClass : function(className){
7669 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7673 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7674 * @param {String} oldClassName The CSS class to replace
7675 * @param {String} newClassName The replacement CSS class
7676 * @return {Roo.Element} this
7678 replaceClass : function(oldClassName, newClassName){
7679 this.removeClass(oldClassName);
7680 this.addClass(newClassName);
7685 * Returns an object with properties matching the styles requested.
7686 * For example, el.getStyles('color', 'font-size', 'width') might return
7687 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7688 * @param {String} style1 A style name
7689 * @param {String} style2 A style name
7690 * @param {String} etc.
7691 * @return {Object} The style object
7693 getStyles : function(){
7694 var a = arguments, len = a.length, r = {};
7695 for(var i = 0; i < len; i++){
7696 r[a[i]] = this.getStyle(a[i]);
7702 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7703 * @param {String} property The style property whose value is returned.
7704 * @return {String} The current value of the style property for this element.
7706 getStyle : function(){
7707 return view && view.getComputedStyle ?
7709 var el = this.dom, v, cs, camel;
7710 if(prop == 'float'){
7713 if(el.style && (v = el.style[prop])){
7716 if(cs = view.getComputedStyle(el, "")){
7717 if(!(camel = propCache[prop])){
7718 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7725 var el = this.dom, v, cs, camel;
7726 if(prop == 'opacity'){
7727 if(typeof el.style.filter == 'string'){
7728 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7730 var fv = parseFloat(m[1]);
7732 return fv ? fv / 100 : 0;
7737 }else if(prop == 'float'){
7738 prop = "styleFloat";
7740 if(!(camel = propCache[prop])){
7741 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7743 if(v = el.style[camel]){
7746 if(cs = el.currentStyle){
7754 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7755 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7756 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7757 * @return {Roo.Element} this
7759 setStyle : function(prop, value){
7760 if(typeof prop == "string"){
7762 if (prop == 'float') {
7763 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7768 if(!(camel = propCache[prop])){
7769 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7772 if(camel == 'opacity') {
7773 this.setOpacity(value);
7775 this.dom.style[camel] = value;
7778 for(var style in prop){
7779 if(typeof prop[style] != "function"){
7780 this.setStyle(style, prop[style]);
7788 * More flexible version of {@link #setStyle} for setting style properties.
7789 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7790 * a function which returns such a specification.
7791 * @return {Roo.Element} this
7793 applyStyles : function(style){
7794 Roo.DomHelper.applyStyles(this.dom, style);
7799 * 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).
7800 * @return {Number} The X position of the element
7803 return D.getX(this.dom);
7807 * 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).
7808 * @return {Number} The Y position of the element
7811 return D.getY(this.dom);
7815 * 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).
7816 * @return {Array} The XY position of the element
7819 return D.getXY(this.dom);
7823 * 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).
7824 * @param {Number} The X position of the element
7825 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826 * @return {Roo.Element} this
7828 setX : function(x, animate){
7830 D.setX(this.dom, x);
7832 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7838 * 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).
7839 * @param {Number} The Y position of the element
7840 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7841 * @return {Roo.Element} this
7843 setY : function(y, animate){
7845 D.setY(this.dom, y);
7847 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7853 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7854 * @param {String} left The left CSS property value
7855 * @return {Roo.Element} this
7857 setLeft : function(left){
7858 this.setStyle("left", this.addUnits(left));
7863 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7864 * @param {String} top The top CSS property value
7865 * @return {Roo.Element} this
7867 setTop : function(top){
7868 this.setStyle("top", this.addUnits(top));
7873 * Sets the element's CSS right style.
7874 * @param {String} right The right CSS property value
7875 * @return {Roo.Element} this
7877 setRight : function(right){
7878 this.setStyle("right", this.addUnits(right));
7883 * Sets the element's CSS bottom style.
7884 * @param {String} bottom The bottom CSS property value
7885 * @return {Roo.Element} this
7887 setBottom : function(bottom){
7888 this.setStyle("bottom", this.addUnits(bottom));
7893 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7894 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7895 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7896 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7897 * @return {Roo.Element} this
7899 setXY : function(pos, animate){
7901 D.setXY(this.dom, pos);
7903 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7909 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7910 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7911 * @param {Number} x X value for new position (coordinates are page-based)
7912 * @param {Number} y Y value for new position (coordinates are page-based)
7913 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7914 * @return {Roo.Element} this
7916 setLocation : function(x, y, animate){
7917 this.setXY([x, y], this.preanim(arguments, 2));
7922 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7923 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7924 * @param {Number} x X value for new position (coordinates are page-based)
7925 * @param {Number} y Y value for new position (coordinates are page-based)
7926 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7927 * @return {Roo.Element} this
7929 moveTo : function(x, y, animate){
7930 this.setXY([x, y], this.preanim(arguments, 2));
7935 * Returns the region of the given element.
7936 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7937 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7939 getRegion : function(){
7940 return D.getRegion(this.dom);
7944 * Returns the offset height of the element
7945 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7946 * @return {Number} The element's height
7948 getHeight : function(contentHeight){
7949 var h = this.dom.offsetHeight || 0;
7950 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7954 * Returns the offset width of the element
7955 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7956 * @return {Number} The element's width
7958 getWidth : function(contentWidth){
7959 var w = this.dom.offsetWidth || 0;
7960 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7964 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7965 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7966 * if a height has not been set using CSS.
7969 getComputedHeight : function(){
7970 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7972 h = parseInt(this.getStyle('height'), 10) || 0;
7973 if(!this.isBorderBox()){
7974 h += this.getFrameWidth('tb');
7981 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7982 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7983 * if a width has not been set using CSS.
7986 getComputedWidth : function(){
7987 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7989 w = parseInt(this.getStyle('width'), 10) || 0;
7990 if(!this.isBorderBox()){
7991 w += this.getFrameWidth('lr');
7998 * Returns the size of the element.
7999 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8000 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8002 getSize : function(contentSize){
8003 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8007 * Returns the width and height of the viewport.
8008 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8010 getViewSize : function(){
8011 var d = this.dom, doc = document, aw = 0, ah = 0;
8012 if(d == doc || d == doc.body){
8013 return {width : D.getViewWidth(), height: D.getViewHeight()};
8016 width : d.clientWidth,
8017 height: d.clientHeight
8023 * Returns the value of the "value" attribute
8024 * @param {Boolean} asNumber true to parse the value as a number
8025 * @return {String/Number}
8027 getValue : function(asNumber){
8028 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8032 adjustWidth : function(width){
8033 if(typeof width == "number"){
8034 if(this.autoBoxAdjust && !this.isBorderBox()){
8035 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8045 adjustHeight : function(height){
8046 if(typeof height == "number"){
8047 if(this.autoBoxAdjust && !this.isBorderBox()){
8048 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8058 * Set the width of the element
8059 * @param {Number} width The new width
8060 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8061 * @return {Roo.Element} this
8063 setWidth : function(width, animate){
8064 width = this.adjustWidth(width);
8066 this.dom.style.width = this.addUnits(width);
8068 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8074 * Set the height of the element
8075 * @param {Number} height The new height
8076 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8077 * @return {Roo.Element} this
8079 setHeight : function(height, animate){
8080 height = this.adjustHeight(height);
8082 this.dom.style.height = this.addUnits(height);
8084 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8090 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8091 * @param {Number} width The new width
8092 * @param {Number} height The new height
8093 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8094 * @return {Roo.Element} this
8096 setSize : function(width, height, animate){
8097 if(typeof width == "object"){ // in case of object from getSize()
8098 height = width.height; width = width.width;
8100 width = this.adjustWidth(width); height = this.adjustHeight(height);
8102 this.dom.style.width = this.addUnits(width);
8103 this.dom.style.height = this.addUnits(height);
8105 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8111 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8112 * @param {Number} x X value for new position (coordinates are page-based)
8113 * @param {Number} y Y value for new position (coordinates are page-based)
8114 * @param {Number} width The new width
8115 * @param {Number} height The new height
8116 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8117 * @return {Roo.Element} this
8119 setBounds : function(x, y, width, height, animate){
8121 this.setSize(width, height);
8122 this.setLocation(x, y);
8124 width = this.adjustWidth(width); height = this.adjustHeight(height);
8125 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8126 this.preanim(arguments, 4), 'motion');
8132 * 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.
8133 * @param {Roo.lib.Region} region The region to fill
8134 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8135 * @return {Roo.Element} this
8137 setRegion : function(region, animate){
8138 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8143 * Appends an event handler
8145 * @param {String} eventName The type of event to append
8146 * @param {Function} fn The method the event invokes
8147 * @param {Object} scope (optional) The scope (this object) of the fn
8148 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8150 addListener : function(eventName, fn, scope, options){
8152 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8157 * Removes an event handler from this element
8158 * @param {String} eventName the type of event to remove
8159 * @param {Function} fn the method the event invokes
8160 * @return {Roo.Element} this
8162 removeListener : function(eventName, fn){
8163 Roo.EventManager.removeListener(this.dom, eventName, fn);
8168 * Removes all previous added listeners from this element
8169 * @return {Roo.Element} this
8171 removeAllListeners : function(){
8172 E.purgeElement(this.dom);
8176 relayEvent : function(eventName, observable){
8177 this.on(eventName, function(e){
8178 observable.fireEvent(eventName, e);
8183 * Set the opacity of the element
8184 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8185 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8186 * @return {Roo.Element} this
8188 setOpacity : function(opacity, animate){
8190 var s = this.dom.style;
8193 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8194 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8196 s.opacity = opacity;
8199 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8205 * Gets the left X coordinate
8206 * @param {Boolean} local True to get the local css position instead of page coordinate
8209 getLeft : function(local){
8213 return parseInt(this.getStyle("left"), 10) || 0;
8218 * Gets the right X coordinate of the element (element X position + element width)
8219 * @param {Boolean} local True to get the local css position instead of page coordinate
8222 getRight : function(local){
8224 return this.getX() + this.getWidth();
8226 return (this.getLeft(true) + this.getWidth()) || 0;
8231 * Gets the top Y coordinate
8232 * @param {Boolean} local True to get the local css position instead of page coordinate
8235 getTop : function(local) {
8239 return parseInt(this.getStyle("top"), 10) || 0;
8244 * Gets the bottom Y coordinate of the element (element Y position + element height)
8245 * @param {Boolean} local True to get the local css position instead of page coordinate
8248 getBottom : function(local){
8250 return this.getY() + this.getHeight();
8252 return (this.getTop(true) + this.getHeight()) || 0;
8257 * Initializes positioning on this element. If a desired position is not passed, it will make the
8258 * the element positioned relative IF it is not already positioned.
8259 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8260 * @param {Number} zIndex (optional) The zIndex to apply
8261 * @param {Number} x (optional) Set the page X position
8262 * @param {Number} y (optional) Set the page Y position
8264 position : function(pos, zIndex, x, y){
8266 if(this.getStyle('position') == 'static'){
8267 this.setStyle('position', 'relative');
8270 this.setStyle("position", pos);
8273 this.setStyle("z-index", zIndex);
8275 if(x !== undefined && y !== undefined){
8277 }else if(x !== undefined){
8279 }else if(y !== undefined){
8285 * Clear positioning back to the default when the document was loaded
8286 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8287 * @return {Roo.Element} this
8289 clearPositioning : function(value){
8297 "position" : "static"
8303 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8304 * snapshot before performing an update and then restoring the element.
8307 getPositioning : function(){
8308 var l = this.getStyle("left");
8309 var t = this.getStyle("top");
8311 "position" : this.getStyle("position"),
8313 "right" : l ? "" : this.getStyle("right"),
8315 "bottom" : t ? "" : this.getStyle("bottom"),
8316 "z-index" : this.getStyle("z-index")
8321 * Gets the width of the border(s) for the specified side(s)
8322 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8323 * passing lr would get the border (l)eft width + the border (r)ight width.
8324 * @return {Number} The width of the sides passed added together
8326 getBorderWidth : function(side){
8327 return this.addStyles(side, El.borders);
8331 * Gets the width of the padding(s) for the specified side(s)
8332 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8333 * passing lr would get the padding (l)eft + the padding (r)ight.
8334 * @return {Number} The padding of the sides passed added together
8336 getPadding : function(side){
8337 return this.addStyles(side, El.paddings);
8341 * Set positioning with an object returned by getPositioning().
8342 * @param {Object} posCfg
8343 * @return {Roo.Element} this
8345 setPositioning : function(pc){
8346 this.applyStyles(pc);
8347 if(pc.right == "auto"){
8348 this.dom.style.right = "";
8350 if(pc.bottom == "auto"){
8351 this.dom.style.bottom = "";
8357 fixDisplay : function(){
8358 if(this.getStyle("display") == "none"){
8359 this.setStyle("visibility", "hidden");
8360 this.setStyle("display", this.originalDisplay); // first try reverting to default
8361 if(this.getStyle("display") == "none"){ // if that fails, default to block
8362 this.setStyle("display", "block");
8368 * Quick set left and top adding default units
8369 * @param {String} left The left CSS property value
8370 * @param {String} top The top CSS property value
8371 * @return {Roo.Element} this
8373 setLeftTop : function(left, top){
8374 this.dom.style.left = this.addUnits(left);
8375 this.dom.style.top = this.addUnits(top);
8380 * Move this element relative to its current position.
8381 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8382 * @param {Number} distance How far to move the element in pixels
8383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8384 * @return {Roo.Element} this
8386 move : function(direction, distance, animate){
8387 var xy = this.getXY();
8388 direction = direction.toLowerCase();
8392 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8396 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8401 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8406 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8413 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8414 * @return {Roo.Element} this
8417 if(!this.isClipped){
8418 this.isClipped = true;
8419 this.originalClip = {
8420 "o": this.getStyle("overflow"),
8421 "x": this.getStyle("overflow-x"),
8422 "y": this.getStyle("overflow-y")
8424 this.setStyle("overflow", "hidden");
8425 this.setStyle("overflow-x", "hidden");
8426 this.setStyle("overflow-y", "hidden");
8432 * Return clipping (overflow) to original clipping before clip() was called
8433 * @return {Roo.Element} this
8435 unclip : function(){
8437 this.isClipped = false;
8438 var o = this.originalClip;
8439 if(o.o){this.setStyle("overflow", o.o);}
8440 if(o.x){this.setStyle("overflow-x", o.x);}
8441 if(o.y){this.setStyle("overflow-y", o.y);}
8448 * Gets the x,y coordinates specified by the anchor position on the element.
8449 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8450 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8451 * {width: (target width), height: (target height)} (defaults to the element's current size)
8452 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8453 * @return {Array} [x, y] An array containing the element's x and y coordinates
8455 getAnchorXY : function(anchor, local, s){
8456 //Passing a different size is useful for pre-calculating anchors,
8457 //especially for anchored animations that change the el size.
8459 var w, h, vp = false;
8462 if(d == document.body || d == document){
8464 w = D.getViewWidth(); h = D.getViewHeight();
8466 w = this.getWidth(); h = this.getHeight();
8469 w = s.width; h = s.height;
8471 var x = 0, y = 0, r = Math.round;
8472 switch((anchor || "tl").toLowerCase()){
8514 var sc = this.getScroll();
8515 return [x + sc.left, y + sc.top];
8517 //Add the element's offset xy
8518 var o = this.getXY();
8519 return [x+o[0], y+o[1]];
8523 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8524 * supported position values.
8525 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8526 * @param {String} position The position to align to.
8527 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8528 * @return {Array} [x, y]
8530 getAlignToXY : function(el, p, o){
8534 throw "Element.alignTo with an element that doesn't exist";
8536 var c = false; //constrain to viewport
8537 var p1 = "", p2 = "";
8544 }else if(p.indexOf("-") == -1){
8547 p = p.toLowerCase();
8548 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8550 throw "Element.alignTo with an invalid alignment " + p;
8552 p1 = m[1]; p2 = m[2]; c = !!m[3];
8554 //Subtract the aligned el's internal xy from the target's offset xy
8555 //plus custom offset to get the aligned el's new offset xy
8556 var a1 = this.getAnchorXY(p1, true);
8557 var a2 = el.getAnchorXY(p2, false);
8558 var x = a2[0] - a1[0] + o[0];
8559 var y = a2[1] - a1[1] + o[1];
8561 //constrain the aligned el to viewport if necessary
8562 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8563 // 5px of margin for ie
8564 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8566 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8567 //perpendicular to the vp border, allow the aligned el to slide on that border,
8568 //otherwise swap the aligned el to the opposite border of the target.
8569 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8570 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8571 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8572 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8575 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8576 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8578 if((x+w) > dw + scrollX){
8579 x = swapX ? r.left-w : dw+scrollX-w;
8582 x = swapX ? r.right : scrollX;
8584 if((y+h) > dh + scrollY){
8585 y = swapY ? r.top-h : dh+scrollY-h;
8588 y = swapY ? r.bottom : scrollY;
8595 getConstrainToXY : function(){
8596 var os = {top:0, left:0, bottom:0, right: 0};
8598 return function(el, local, offsets, proposedXY){
8600 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8602 var vw, vh, vx = 0, vy = 0;
8603 if(el.dom == document.body || el.dom == document){
8604 vw = Roo.lib.Dom.getViewWidth();
8605 vh = Roo.lib.Dom.getViewHeight();
8607 vw = el.dom.clientWidth;
8608 vh = el.dom.clientHeight;
8610 var vxy = el.getXY();
8616 var s = el.getScroll();
8618 vx += offsets.left + s.left;
8619 vy += offsets.top + s.top;
8621 vw -= offsets.right;
8622 vh -= offsets.bottom;
8627 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8628 var x = xy[0], y = xy[1];
8629 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8631 // only move it if it needs it
8634 // first validate right/bottom
8643 // then make sure top/left isn't negative
8652 return moved ? [x, y] : false;
8657 adjustForConstraints : function(xy, parent, offsets){
8658 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8662 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8663 * document it aligns it to the viewport.
8664 * The position parameter is optional, and can be specified in any one of the following formats:
8666 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8667 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8668 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8669 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8670 * <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
8671 * element's anchor point, and the second value is used as the target's anchor point.</li>
8673 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8674 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8675 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8676 * that specified in order to enforce the viewport constraints.
8677 * Following are all of the supported anchor positions:
8680 ----- -----------------------------
8681 tl The top left corner (default)
8682 t The center of the top edge
8683 tr The top right corner
8684 l The center of the left edge
8685 c In the center of the element
8686 r The center of the right edge
8687 bl The bottom left corner
8688 b The center of the bottom edge
8689 br The bottom right corner
8693 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8694 el.alignTo("other-el");
8696 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8697 el.alignTo("other-el", "tr?");
8699 // align the bottom right corner of el with the center left edge of other-el
8700 el.alignTo("other-el", "br-l?");
8702 // align the center of el with the bottom left corner of other-el and
8703 // adjust the x position by -6 pixels (and the y position by 0)
8704 el.alignTo("other-el", "c-bl", [-6, 0]);
8706 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8707 * @param {String} position The position to align to.
8708 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8709 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8710 * @return {Roo.Element} this
8712 alignTo : function(element, position, offsets, animate){
8713 var xy = this.getAlignToXY(element, position, offsets);
8714 this.setXY(xy, this.preanim(arguments, 3));
8719 * Anchors an element to another element and realigns it when the window is resized.
8720 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8721 * @param {String} position The position to align to.
8722 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8723 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8724 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8725 * is a number, it is used as the buffer delay (defaults to 50ms).
8726 * @param {Function} callback The function to call after the animation finishes
8727 * @return {Roo.Element} this
8729 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8730 var action = function(){
8731 this.alignTo(el, alignment, offsets, animate);
8732 Roo.callback(callback, this);
8734 Roo.EventManager.onWindowResize(action, this);
8735 var tm = typeof monitorScroll;
8736 if(tm != 'undefined'){
8737 Roo.EventManager.on(window, 'scroll', action, this,
8738 {buffer: tm == 'number' ? monitorScroll : 50});
8740 action.call(this); // align immediately
8744 * Clears any opacity settings from this element. Required in some cases for IE.
8745 * @return {Roo.Element} this
8747 clearOpacity : function(){
8748 if (window.ActiveXObject) {
8749 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8750 this.dom.style.filter = "";
8753 this.dom.style.opacity = "";
8754 this.dom.style["-moz-opacity"] = "";
8755 this.dom.style["-khtml-opacity"] = "";
8761 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8762 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8763 * @return {Roo.Element} this
8765 hide : function(animate){
8766 this.setVisible(false, this.preanim(arguments, 0));
8771 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8772 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8773 * @return {Roo.Element} this
8775 show : function(animate){
8776 this.setVisible(true, this.preanim(arguments, 0));
8781 * @private Test if size has a unit, otherwise appends the default
8783 addUnits : function(size){
8784 return Roo.Element.addUnits(size, this.defaultUnit);
8788 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8789 * @return {Roo.Element} this
8791 beginMeasure : function(){
8793 if(el.offsetWidth || el.offsetHeight){
8794 return this; // offsets work already
8797 var p = this.dom, b = document.body; // start with this element
8798 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8799 var pe = Roo.get(p);
8800 if(pe.getStyle('display') == 'none'){
8801 changed.push({el: p, visibility: pe.getStyle("visibility")});
8802 p.style.visibility = "hidden";
8803 p.style.display = "block";
8807 this._measureChanged = changed;
8813 * Restores displays to before beginMeasure was called
8814 * @return {Roo.Element} this
8816 endMeasure : function(){
8817 var changed = this._measureChanged;
8819 for(var i = 0, len = changed.length; i < len; i++) {
8821 r.el.style.visibility = r.visibility;
8822 r.el.style.display = "none";
8824 this._measureChanged = null;
8830 * Update the innerHTML of this element, optionally searching for and processing scripts
8831 * @param {String} html The new HTML
8832 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8833 * @param {Function} callback For async script loading you can be noticed when the update completes
8834 * @return {Roo.Element} this
8836 update : function(html, loadScripts, callback){
8837 if(typeof html == "undefined"){
8840 if(loadScripts !== true){
8841 this.dom.innerHTML = html;
8842 if(typeof callback == "function"){
8850 html += '<span id="' + id + '"></span>';
8852 E.onAvailable(id, function(){
8853 var hd = document.getElementsByTagName("head")[0];
8854 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8855 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8856 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8859 while(match = re.exec(html)){
8860 var attrs = match[1];
8861 var srcMatch = attrs ? attrs.match(srcRe) : false;
8862 if(srcMatch && srcMatch[2]){
8863 var s = document.createElement("script");
8864 s.src = srcMatch[2];
8865 var typeMatch = attrs.match(typeRe);
8866 if(typeMatch && typeMatch[2]){
8867 s.type = typeMatch[2];
8870 }else if(match[2] && match[2].length > 0){
8871 if(window.execScript) {
8872 window.execScript(match[2]);
8880 window.eval(match[2]);
8884 var el = document.getElementById(id);
8885 if(el){el.parentNode.removeChild(el);}
8886 if(typeof callback == "function"){
8890 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8895 * Direct access to the UpdateManager update() method (takes the same parameters).
8896 * @param {String/Function} url The url for this request or a function to call to get the url
8897 * @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}
8898 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8899 * @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.
8900 * @return {Roo.Element} this
8903 var um = this.getUpdateManager();
8904 um.update.apply(um, arguments);
8909 * Gets this element's UpdateManager
8910 * @return {Roo.UpdateManager} The UpdateManager
8912 getUpdateManager : function(){
8913 if(!this.updateManager){
8914 this.updateManager = new Roo.UpdateManager(this);
8916 return this.updateManager;
8920 * Disables text selection for this element (normalized across browsers)
8921 * @return {Roo.Element} this
8923 unselectable : function(){
8924 this.dom.unselectable = "on";
8925 this.swallowEvent("selectstart", true);
8926 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8927 this.addClass("x-unselectable");
8932 * Calculates the x, y to center this element on the screen
8933 * @return {Array} The x, y values [x, y]
8935 getCenterXY : function(){
8936 return this.getAlignToXY(document, 'c-c');
8940 * Centers the Element in either the viewport, or another Element.
8941 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8943 center : function(centerIn){
8944 this.alignTo(centerIn || document, 'c-c');
8949 * Tests various css rules/browsers to determine if this element uses a border box
8952 isBorderBox : function(){
8953 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8957 * Return a box {x, y, width, height} that can be used to set another elements
8958 * size/location to match this element.
8959 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8960 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8961 * @return {Object} box An object in the format {x, y, width, height}
8963 getBox : function(contentBox, local){
8968 var left = parseInt(this.getStyle("left"), 10) || 0;
8969 var top = parseInt(this.getStyle("top"), 10) || 0;
8972 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8974 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8976 var l = this.getBorderWidth("l")+this.getPadding("l");
8977 var r = this.getBorderWidth("r")+this.getPadding("r");
8978 var t = this.getBorderWidth("t")+this.getPadding("t");
8979 var b = this.getBorderWidth("b")+this.getPadding("b");
8980 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)};
8982 bx.right = bx.x + bx.width;
8983 bx.bottom = bx.y + bx.height;
8988 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8989 for more information about the sides.
8990 * @param {String} sides
8993 getFrameWidth : function(sides, onlyContentBox){
8994 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8998 * 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.
8999 * @param {Object} box The box to fill {x, y, width, height}
9000 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9001 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9002 * @return {Roo.Element} this
9004 setBox : function(box, adjust, animate){
9005 var w = box.width, h = box.height;
9006 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9007 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9008 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9010 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9015 * Forces the browser to repaint this element
9016 * @return {Roo.Element} this
9018 repaint : function(){
9020 this.addClass("x-repaint");
9021 setTimeout(function(){
9022 Roo.get(dom).removeClass("x-repaint");
9028 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9029 * then it returns the calculated width of the sides (see getPadding)
9030 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9031 * @return {Object/Number}
9033 getMargins : function(side){
9036 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9037 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9038 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9039 right: parseInt(this.getStyle("margin-right"), 10) || 0
9042 return this.addStyles(side, El.margins);
9047 addStyles : function(sides, styles){
9049 for(var i = 0, len = sides.length; i < len; i++){
9050 v = this.getStyle(styles[sides.charAt(i)]);
9052 w = parseInt(v, 10);
9060 * Creates a proxy element of this element
9061 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9062 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9063 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9064 * @return {Roo.Element} The new proxy element
9066 createProxy : function(config, renderTo, matchBox){
9068 renderTo = Roo.getDom(renderTo);
9070 renderTo = document.body;
9072 config = typeof config == "object" ?
9073 config : {tag : "div", cls: config};
9074 var proxy = Roo.DomHelper.append(renderTo, config, true);
9076 proxy.setBox(this.getBox());
9082 * Puts a mask over this element to disable user interaction. Requires core.css.
9083 * This method can only be applied to elements which accept child nodes.
9084 * @param {String} msg (optional) A message to display in the mask
9085 * @param {String} msgCls (optional) A css class to apply to the msg element
9086 * @return {Element} The mask element
9088 mask : function(msg, msgCls)
9090 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9091 this.setStyle("position", "relative");
9094 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9096 this.addClass("x-masked");
9097 this._mask.setDisplayed(true);
9102 while (dom && dom.style) {
9103 if (!isNaN(parseInt(dom.style.zIndex))) {
9104 z = Math.max(z, parseInt(dom.style.zIndex));
9106 dom = dom.parentNode;
9108 // if we are masking the body - then it hides everything..
9109 if (this.dom == document.body) {
9111 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9112 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9115 if(typeof msg == 'string'){
9117 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9119 var mm = this._maskMsg;
9120 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9121 if (mm.dom.firstChild) { // weird IE issue?
9122 mm.dom.firstChild.innerHTML = msg;
9124 mm.setDisplayed(true);
9126 mm.setStyle('z-index', z + 102);
9128 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9129 this._mask.setHeight(this.getHeight());
9131 this._mask.setStyle('z-index', z + 100);
9137 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9138 * it is cached for reuse.
9140 unmask : function(removeEl){
9142 if(removeEl === true){
9143 this._mask.remove();
9146 this._maskMsg.remove();
9147 delete this._maskMsg;
9150 this._mask.setDisplayed(false);
9152 this._maskMsg.setDisplayed(false);
9156 this.removeClass("x-masked");
9160 * Returns true if this element is masked
9163 isMasked : function(){
9164 return this._mask && this._mask.isVisible();
9168 * Creates an iframe shim for this element to keep selects and other windowed objects from
9170 * @return {Roo.Element} The new shim element
9172 createShim : function(){
9173 var el = document.createElement('iframe');
9174 el.frameBorder = 'no';
9175 el.className = 'roo-shim';
9176 if(Roo.isIE && Roo.isSecure){
9177 el.src = Roo.SSL_SECURE_URL;
9179 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9180 shim.autoBoxAdjust = false;
9185 * Removes this element from the DOM and deletes it from the cache
9187 remove : function(){
9188 if(this.dom.parentNode){
9189 this.dom.parentNode.removeChild(this.dom);
9191 delete El.cache[this.dom.id];
9195 * Sets up event handlers to add and remove a css class when the mouse is over this element
9196 * @param {String} className
9197 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9198 * mouseout events for children elements
9199 * @return {Roo.Element} this
9201 addClassOnOver : function(className, preventFlicker){
9202 this.on("mouseover", function(){
9203 Roo.fly(this, '_internal').addClass(className);
9205 var removeFn = function(e){
9206 if(preventFlicker !== true || !e.within(this, true)){
9207 Roo.fly(this, '_internal').removeClass(className);
9210 this.on("mouseout", removeFn, this.dom);
9215 * Sets up event handlers to add and remove a css class when this element has the focus
9216 * @param {String} className
9217 * @return {Roo.Element} this
9219 addClassOnFocus : function(className){
9220 this.on("focus", function(){
9221 Roo.fly(this, '_internal').addClass(className);
9223 this.on("blur", function(){
9224 Roo.fly(this, '_internal').removeClass(className);
9229 * 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)
9230 * @param {String} className
9231 * @return {Roo.Element} this
9233 addClassOnClick : function(className){
9235 this.on("mousedown", function(){
9236 Roo.fly(dom, '_internal').addClass(className);
9237 var d = Roo.get(document);
9238 var fn = function(){
9239 Roo.fly(dom, '_internal').removeClass(className);
9240 d.removeListener("mouseup", fn);
9242 d.on("mouseup", fn);
9248 * Stops the specified event from bubbling and optionally prevents the default action
9249 * @param {String} eventName
9250 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9251 * @return {Roo.Element} this
9253 swallowEvent : function(eventName, preventDefault){
9254 var fn = function(e){
9255 e.stopPropagation();
9260 if(eventName instanceof Array){
9261 for(var i = 0, len = eventName.length; i < len; i++){
9262 this.on(eventName[i], fn);
9266 this.on(eventName, fn);
9273 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9276 * Sizes this element to its parent element's dimensions performing
9277 * neccessary box adjustments.
9278 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9279 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9280 * @return {Roo.Element} this
9282 fitToParent : function(monitorResize, targetParent) {
9283 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9284 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9285 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9288 var p = Roo.get(targetParent || this.dom.parentNode);
9289 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9290 if (monitorResize === true) {
9291 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9292 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9298 * Gets the next sibling, skipping text nodes
9299 * @return {HTMLElement} The next sibling or null
9301 getNextSibling : function(){
9302 var n = this.dom.nextSibling;
9303 while(n && n.nodeType != 1){
9310 * Gets the previous sibling, skipping text nodes
9311 * @return {HTMLElement} The previous sibling or null
9313 getPrevSibling : function(){
9314 var n = this.dom.previousSibling;
9315 while(n && n.nodeType != 1){
9316 n = n.previousSibling;
9323 * Appends the passed element(s) to this element
9324 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9325 * @return {Roo.Element} this
9327 appendChild: function(el){
9334 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9335 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9336 * automatically generated with the specified attributes.
9337 * @param {HTMLElement} insertBefore (optional) a child element of this element
9338 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9339 * @return {Roo.Element} The new child element
9341 createChild: function(config, insertBefore, returnDom){
9342 config = config || {tag:'div'};
9344 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9346 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9350 * Appends this element to the passed element
9351 * @param {String/HTMLElement/Element} el The new parent element
9352 * @return {Roo.Element} this
9354 appendTo: function(el){
9355 el = Roo.getDom(el);
9356 el.appendChild(this.dom);
9361 * Inserts this element before the passed element in the DOM
9362 * @param {String/HTMLElement/Element} el The element to insert before
9363 * @return {Roo.Element} this
9365 insertBefore: function(el){
9366 el = Roo.getDom(el);
9367 el.parentNode.insertBefore(this.dom, el);
9372 * Inserts this element after the passed element in the DOM
9373 * @param {String/HTMLElement/Element} el The element to insert after
9374 * @return {Roo.Element} this
9376 insertAfter: function(el){
9377 el = Roo.getDom(el);
9378 el.parentNode.insertBefore(this.dom, el.nextSibling);
9383 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9384 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9385 * @return {Roo.Element} The new child
9387 insertFirst: function(el, returnDom){
9389 if(typeof el == 'object' && !el.nodeType){ // dh config
9390 return this.createChild(el, this.dom.firstChild, returnDom);
9392 el = Roo.getDom(el);
9393 this.dom.insertBefore(el, this.dom.firstChild);
9394 return !returnDom ? Roo.get(el) : el;
9399 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9400 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9401 * @param {String} where (optional) 'before' or 'after' defaults to before
9402 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9403 * @return {Roo.Element} the inserted Element
9405 insertSibling: function(el, where, returnDom){
9406 where = where ? where.toLowerCase() : 'before';
9408 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9410 if(typeof el == 'object' && !el.nodeType){ // dh config
9411 if(where == 'after' && !this.dom.nextSibling){
9412 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9414 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9418 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9419 where == 'before' ? this.dom : this.dom.nextSibling);
9428 * Creates and wraps this element with another element
9429 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9430 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9431 * @return {HTMLElement/Element} The newly created wrapper element
9433 wrap: function(config, returnDom){
9435 config = {tag: "div"};
9437 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9438 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9443 * Replaces the passed element with this element
9444 * @param {String/HTMLElement/Element} el The element to replace
9445 * @return {Roo.Element} this
9447 replace: function(el){
9449 this.insertBefore(el);
9455 * Inserts an html fragment into this element
9456 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9457 * @param {String} html The HTML fragment
9458 * @param {Boolean} returnEl True to return an Roo.Element
9459 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9461 insertHtml : function(where, html, returnEl){
9462 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9463 return returnEl ? Roo.get(el) : el;
9467 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9468 * @param {Object} o The object with the attributes
9469 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9470 * @return {Roo.Element} this
9472 set : function(o, useSet){
9474 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9476 if(attr == "style" || typeof o[attr] == "function") { continue; }
9478 el.className = o["cls"];
9481 el.setAttribute(attr, o[attr]);
9488 Roo.DomHelper.applyStyles(el, o.style);
9494 * Convenience method for constructing a KeyMap
9495 * @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:
9496 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9497 * @param {Function} fn The function to call
9498 * @param {Object} scope (optional) The scope of the function
9499 * @return {Roo.KeyMap} The KeyMap created
9501 addKeyListener : function(key, fn, scope){
9503 if(typeof key != "object" || key instanceof Array){
9519 return new Roo.KeyMap(this, config);
9523 * Creates a KeyMap for this element
9524 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9525 * @return {Roo.KeyMap} The KeyMap created
9527 addKeyMap : function(config){
9528 return new Roo.KeyMap(this, config);
9532 * Returns true if this element is scrollable.
9535 isScrollable : function(){
9537 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9541 * 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().
9542 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9543 * @param {Number} value The new scroll value
9544 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9545 * @return {Element} this
9548 scrollTo : function(side, value, animate){
9549 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9551 this.dom[prop] = value;
9553 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9554 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9560 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9561 * within this element's scrollable range.
9562 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9563 * @param {Number} distance How far to scroll the element in pixels
9564 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9565 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9566 * was scrolled as far as it could go.
9568 scroll : function(direction, distance, animate){
9569 if(!this.isScrollable()){
9573 var l = el.scrollLeft, t = el.scrollTop;
9574 var w = el.scrollWidth, h = el.scrollHeight;
9575 var cw = el.clientWidth, ch = el.clientHeight;
9576 direction = direction.toLowerCase();
9577 var scrolled = false;
9578 var a = this.preanim(arguments, 2);
9583 var v = Math.min(l + distance, w-cw);
9584 this.scrollTo("left", v, a);
9591 var v = Math.max(l - distance, 0);
9592 this.scrollTo("left", v, a);
9600 var v = Math.max(t - distance, 0);
9601 this.scrollTo("top", v, a);
9609 var v = Math.min(t + distance, h-ch);
9610 this.scrollTo("top", v, a);
9619 * Translates the passed page coordinates into left/top css values for this element
9620 * @param {Number/Array} x The page x or an array containing [x, y]
9621 * @param {Number} y The page y
9622 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9624 translatePoints : function(x, y){
9625 if(typeof x == 'object' || x instanceof Array){
9628 var p = this.getStyle('position');
9629 var o = this.getXY();
9631 var l = parseInt(this.getStyle('left'), 10);
9632 var t = parseInt(this.getStyle('top'), 10);
9635 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9638 t = (p == "relative") ? 0 : this.dom.offsetTop;
9641 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9645 * Returns the current scroll position of the element.
9646 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9648 getScroll : function(){
9649 var d = this.dom, doc = document;
9650 if(d == doc || d == doc.body){
9651 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9652 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9653 return {left: l, top: t};
9655 return {left: d.scrollLeft, top: d.scrollTop};
9660 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9661 * are convert to standard 6 digit hex color.
9662 * @param {String} attr The css attribute
9663 * @param {String} defaultValue The default value to use when a valid color isn't found
9664 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9667 getColor : function(attr, defaultValue, prefix){
9668 var v = this.getStyle(attr);
9669 if(!v || v == "transparent" || v == "inherit") {
9670 return defaultValue;
9672 var color = typeof prefix == "undefined" ? "#" : prefix;
9673 if(v.substr(0, 4) == "rgb("){
9674 var rvs = v.slice(4, v.length -1).split(",");
9675 for(var i = 0; i < 3; i++){
9676 var h = parseInt(rvs[i]).toString(16);
9683 if(v.substr(0, 1) == "#"){
9685 for(var i = 1; i < 4; i++){
9686 var c = v.charAt(i);
9689 }else if(v.length == 7){
9690 color += v.substr(1);
9694 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9698 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9699 * gradient background, rounded corners and a 4-way shadow.
9700 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9701 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9702 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9703 * @return {Roo.Element} this
9705 boxWrap : function(cls){
9706 cls = cls || 'x-box';
9707 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9708 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9713 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9714 * @param {String} namespace The namespace in which to look for the attribute
9715 * @param {String} name The attribute name
9716 * @return {String} The attribute value
9718 getAttributeNS : Roo.isIE ? function(ns, name){
9720 var type = typeof d[ns+":"+name];
9721 if(type != 'undefined' && type != 'unknown'){
9722 return d[ns+":"+name];
9725 } : function(ns, name){
9727 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9732 * Sets or Returns the value the dom attribute value
9733 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9734 * @param {String} value (optional) The value to set the attribute to
9735 * @return {String} The attribute value
9737 attr : function(name){
9738 if (arguments.length > 1) {
9739 this.dom.setAttribute(name, arguments[1]);
9740 return arguments[1];
9742 if (typeof(name) == 'object') {
9743 for(var i in name) {
9744 this.attr(i, name[i]);
9750 if (!this.dom.hasAttribute(name)) {
9753 return this.dom.getAttribute(name);
9760 var ep = El.prototype;
9763 * Appends an event handler (Shorthand for addListener)
9764 * @param {String} eventName The type of event to append
9765 * @param {Function} fn The method the event invokes
9766 * @param {Object} scope (optional) The scope (this object) of the fn
9767 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9770 ep.on = ep.addListener;
9772 ep.mon = ep.addListener;
9775 * Removes an event handler from this element (shorthand for removeListener)
9776 * @param {String} eventName the type of event to remove
9777 * @param {Function} fn the method the event invokes
9778 * @return {Roo.Element} this
9781 ep.un = ep.removeListener;
9784 * true to automatically adjust width and height settings for box-model issues (default to true)
9786 ep.autoBoxAdjust = true;
9789 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9792 El.addUnits = function(v, defaultUnit){
9793 if(v === "" || v == "auto"){
9796 if(v === undefined){
9799 if(typeof v == "number" || !El.unitPattern.test(v)){
9800 return v + (defaultUnit || 'px');
9805 // special markup used throughout Roo when box wrapping elements
9806 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>';
9808 * Visibility mode constant - Use visibility to hide element
9814 * Visibility mode constant - Use display to hide element
9820 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9821 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9822 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9834 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9835 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9836 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9837 * @return {Element} The Element object
9840 El.get = function(el){
9842 if(!el){ return null; }
9843 if(typeof el == "string"){ // element id
9844 if(!(elm = document.getElementById(el))){
9847 if(ex = El.cache[el]){
9850 ex = El.cache[el] = new El(elm);
9853 }else if(el.tagName){ // dom element
9857 if(ex = El.cache[id]){
9860 ex = El.cache[id] = new El(el);
9863 }else if(el instanceof El){
9865 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9866 // catch case where it hasn't been appended
9867 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9870 }else if(el.isComposite){
9872 }else if(el instanceof Array){
9873 return El.select(el);
9874 }else if(el == document){
9875 // create a bogus element object representing the document object
9877 var f = function(){};
9878 f.prototype = El.prototype;
9880 docEl.dom = document;
9888 El.uncache = function(el){
9889 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9891 delete El.cache[a[i].id || a[i]];
9897 // Garbage collection - uncache elements/purge listeners on orphaned elements
9898 // so we don't hold a reference and cause the browser to retain them
9899 El.garbageCollect = function(){
9900 if(!Roo.enableGarbageCollector){
9901 clearInterval(El.collectorThread);
9904 for(var eid in El.cache){
9905 var el = El.cache[eid], d = el.dom;
9906 // -------------------------------------------------------
9907 // Determining what is garbage:
9908 // -------------------------------------------------------
9910 // dom node is null, definitely garbage
9911 // -------------------------------------------------------
9913 // no parentNode == direct orphan, definitely garbage
9914 // -------------------------------------------------------
9915 // !d.offsetParent && !document.getElementById(eid)
9916 // display none elements have no offsetParent so we will
9917 // also try to look it up by it's id. However, check
9918 // offsetParent first so we don't do unneeded lookups.
9919 // This enables collection of elements that are not orphans
9920 // directly, but somewhere up the line they have an orphan
9922 // -------------------------------------------------------
9923 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9924 delete El.cache[eid];
9925 if(d && Roo.enableListenerCollection){
9931 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9935 El.Flyweight = function(dom){
9938 El.Flyweight.prototype = El.prototype;
9940 El._flyweights = {};
9942 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9943 * the dom node can be overwritten by other code.
9944 * @param {String/HTMLElement} el The dom node or id
9945 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9946 * prevent conflicts (e.g. internally Roo uses "_internal")
9948 * @return {Element} The shared Element object
9950 El.fly = function(el, named){
9951 named = named || '_global';
9952 el = Roo.getDom(el);
9956 if(!El._flyweights[named]){
9957 El._flyweights[named] = new El.Flyweight();
9959 El._flyweights[named].dom = el;
9960 return El._flyweights[named];
9964 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9965 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9966 * Shorthand of {@link Roo.Element#get}
9967 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9968 * @return {Element} The Element object
9974 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9975 * the dom node can be overwritten by other code.
9976 * Shorthand of {@link Roo.Element#fly}
9977 * @param {String/HTMLElement} el The dom node or id
9978 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9979 * prevent conflicts (e.g. internally Roo uses "_internal")
9981 * @return {Element} The shared Element object
9987 // speedy lookup for elements never to box adjust
9988 var noBoxAdjust = Roo.isStrict ? {
9991 input:1, select:1, textarea:1
9993 if(Roo.isIE || Roo.isGecko){
9994 noBoxAdjust['button'] = 1;
9998 Roo.EventManager.on(window, 'unload', function(){
10000 delete El._flyweights;
10008 Roo.Element.selectorFunction = Roo.DomQuery.select;
10011 Roo.Element.select = function(selector, unique, root){
10013 if(typeof selector == "string"){
10014 els = Roo.Element.selectorFunction(selector, root);
10015 }else if(selector.length !== undefined){
10018 throw "Invalid selector";
10020 if(unique === true){
10021 return new Roo.CompositeElement(els);
10023 return new Roo.CompositeElementLite(els);
10027 * Selects elements based on the passed CSS selector to enable working on them as 1.
10028 * @param {String/Array} selector The CSS selector or an array of elements
10029 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10030 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10031 * @return {CompositeElementLite/CompositeElement}
10035 Roo.select = Roo.Element.select;
10052 * Ext JS Library 1.1.1
10053 * Copyright(c) 2006-2007, Ext JS, LLC.
10055 * Originally Released Under LGPL - original licence link has changed is not relivant.
10058 * <script type="text/javascript">
10063 //Notifies Element that fx methods are available
10064 Roo.enableFx = true;
10068 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10069 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10070 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10071 * Element effects to work.</p><br/>
10073 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10074 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10075 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10076 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10077 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10078 * expected results and should be done with care.</p><br/>
10080 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10081 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10084 ----- -----------------------------
10085 tl The top left corner
10086 t The center of the top edge
10087 tr The top right corner
10088 l The center of the left edge
10089 r The center of the right edge
10090 bl The bottom left corner
10091 b The center of the bottom edge
10092 br The bottom right corner
10094 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10095 * below are common options that can be passed to any Fx method.</b>
10096 * @cfg {Function} callback A function called when the effect is finished
10097 * @cfg {Object} scope The scope of the effect function
10098 * @cfg {String} easing A valid Easing value for the effect
10099 * @cfg {String} afterCls A css class to apply after the effect
10100 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10101 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10102 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10103 * effects that end with the element being visually hidden, ignored otherwise)
10104 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10105 * a function which returns such a specification that will be applied to the Element after the effect finishes
10106 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10107 * @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
10108 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10112 * Slides the element into view. An anchor point can be optionally passed to set the point of
10113 * origin for the slide effect. This function automatically handles wrapping the element with
10114 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10117 // default: slide the element in from the top
10120 // custom: slide the element in from the right with a 2-second duration
10121 el.slideIn('r', { duration: 2 });
10123 // common config options shown with default values
10129 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10130 * @param {Object} options (optional) Object literal with any of the Fx config options
10131 * @return {Roo.Element} The Element
10133 slideIn : function(anchor, o){
10134 var el = this.getFxEl();
10137 el.queueFx(o, function(){
10139 anchor = anchor || "t";
10141 // fix display to visibility
10144 // restore values after effect
10145 var r = this.getFxRestore();
10146 var b = this.getBox();
10147 // fixed size for slide
10151 var wrap = this.fxWrap(r.pos, o, "hidden");
10153 var st = this.dom.style;
10154 st.visibility = "visible";
10155 st.position = "absolute";
10157 // clear out temp styles after slide and unwrap
10158 var after = function(){
10159 el.fxUnwrap(wrap, r.pos, o);
10160 st.width = r.width;
10161 st.height = r.height;
10164 // time to calc the positions
10165 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10167 switch(anchor.toLowerCase()){
10169 wrap.setSize(b.width, 0);
10170 st.left = st.bottom = "0";
10174 wrap.setSize(0, b.height);
10175 st.right = st.top = "0";
10179 wrap.setSize(0, b.height);
10180 wrap.setX(b.right);
10181 st.left = st.top = "0";
10182 a = {width: bw, points: pt};
10185 wrap.setSize(b.width, 0);
10186 wrap.setY(b.bottom);
10187 st.left = st.top = "0";
10188 a = {height: bh, points: pt};
10191 wrap.setSize(0, 0);
10192 st.right = st.bottom = "0";
10193 a = {width: bw, height: bh};
10196 wrap.setSize(0, 0);
10197 wrap.setY(b.y+b.height);
10198 st.right = st.top = "0";
10199 a = {width: bw, height: bh, points: pt};
10202 wrap.setSize(0, 0);
10203 wrap.setXY([b.right, b.bottom]);
10204 st.left = st.top = "0";
10205 a = {width: bw, height: bh, points: pt};
10208 wrap.setSize(0, 0);
10209 wrap.setX(b.x+b.width);
10210 st.left = st.bottom = "0";
10211 a = {width: bw, height: bh, points: pt};
10214 this.dom.style.visibility = "visible";
10217 arguments.callee.anim = wrap.fxanim(a,
10227 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10228 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10229 * 'hidden') but block elements will still take up space in the document. The element must be removed
10230 * from the DOM using the 'remove' config option if desired. This function automatically handles
10231 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10234 // default: slide the element out to the top
10237 // custom: slide the element out to the right with a 2-second duration
10238 el.slideOut('r', { duration: 2 });
10240 // common config options shown with default values
10248 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10249 * @param {Object} options (optional) Object literal with any of the Fx config options
10250 * @return {Roo.Element} The Element
10252 slideOut : function(anchor, o){
10253 var el = this.getFxEl();
10256 el.queueFx(o, function(){
10258 anchor = anchor || "t";
10260 // restore values after effect
10261 var r = this.getFxRestore();
10263 var b = this.getBox();
10264 // fixed size for slide
10268 var wrap = this.fxWrap(r.pos, o, "visible");
10270 var st = this.dom.style;
10271 st.visibility = "visible";
10272 st.position = "absolute";
10276 var after = function(){
10278 el.setDisplayed(false);
10283 el.fxUnwrap(wrap, r.pos, o);
10285 st.width = r.width;
10286 st.height = r.height;
10291 var a, zero = {to: 0};
10292 switch(anchor.toLowerCase()){
10294 st.left = st.bottom = "0";
10295 a = {height: zero};
10298 st.right = st.top = "0";
10302 st.left = st.top = "0";
10303 a = {width: zero, points: {to:[b.right, b.y]}};
10306 st.left = st.top = "0";
10307 a = {height: zero, points: {to:[b.x, b.bottom]}};
10310 st.right = st.bottom = "0";
10311 a = {width: zero, height: zero};
10314 st.right = st.top = "0";
10315 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10318 st.left = st.top = "0";
10319 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10322 st.left = st.bottom = "0";
10323 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10327 arguments.callee.anim = wrap.fxanim(a,
10337 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10338 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10339 * The element must be removed from the DOM using the 'remove' config option if desired.
10345 // common config options shown with default values
10353 * @param {Object} options (optional) Object literal with any of the Fx config options
10354 * @return {Roo.Element} The Element
10356 puff : function(o){
10357 var el = this.getFxEl();
10360 el.queueFx(o, function(){
10361 this.clearOpacity();
10364 // restore values after effect
10365 var r = this.getFxRestore();
10366 var st = this.dom.style;
10368 var after = function(){
10370 el.setDisplayed(false);
10377 el.setPositioning(r.pos);
10378 st.width = r.width;
10379 st.height = r.height;
10384 var width = this.getWidth();
10385 var height = this.getHeight();
10387 arguments.callee.anim = this.fxanim({
10388 width : {to: this.adjustWidth(width * 2)},
10389 height : {to: this.adjustHeight(height * 2)},
10390 points : {by: [-(width * .5), -(height * .5)]},
10392 fontSize: {to:200, unit: "%"}
10403 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10404 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10405 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10411 // all config options shown with default values
10419 * @param {Object} options (optional) Object literal with any of the Fx config options
10420 * @return {Roo.Element} The Element
10422 switchOff : function(o){
10423 var el = this.getFxEl();
10426 el.queueFx(o, function(){
10427 this.clearOpacity();
10430 // restore values after effect
10431 var r = this.getFxRestore();
10432 var st = this.dom.style;
10434 var after = function(){
10436 el.setDisplayed(false);
10442 el.setPositioning(r.pos);
10443 st.width = r.width;
10444 st.height = r.height;
10449 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10450 this.clearOpacity();
10454 points:{by:[0, this.getHeight() * .5]}
10455 }, o, 'motion', 0.3, 'easeIn', after);
10456 }).defer(100, this);
10463 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10464 * changed using the "attr" config option) and then fading back to the original color. If no original
10465 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10468 // default: highlight background to yellow
10471 // custom: highlight foreground text to blue for 2 seconds
10472 el.highlight("0000ff", { attr: 'color', duration: 2 });
10474 // common config options shown with default values
10475 el.highlight("ffff9c", {
10476 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10477 endColor: (current color) or "ffffff",
10482 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10483 * @param {Object} options (optional) Object literal with any of the Fx config options
10484 * @return {Roo.Element} The Element
10486 highlight : function(color, o){
10487 var el = this.getFxEl();
10490 el.queueFx(o, function(){
10491 color = color || "ffff9c";
10492 attr = o.attr || "backgroundColor";
10494 this.clearOpacity();
10497 var origColor = this.getColor(attr);
10498 var restoreColor = this.dom.style[attr];
10499 endColor = (o.endColor || origColor) || "ffffff";
10501 var after = function(){
10502 el.dom.style[attr] = restoreColor;
10507 a[attr] = {from: color, to: endColor};
10508 arguments.callee.anim = this.fxanim(a,
10518 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10521 // default: a single light blue ripple
10524 // custom: 3 red ripples lasting 3 seconds total
10525 el.frame("ff0000", 3, { duration: 3 });
10527 // common config options shown with default values
10528 el.frame("C3DAF9", 1, {
10529 duration: 1 //duration of entire animation (not each individual ripple)
10530 // Note: Easing is not configurable and will be ignored if included
10533 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10534 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10535 * @param {Object} options (optional) Object literal with any of the Fx config options
10536 * @return {Roo.Element} The Element
10538 frame : function(color, count, o){
10539 var el = this.getFxEl();
10542 el.queueFx(o, function(){
10543 color = color || "#C3DAF9";
10544 if(color.length == 6){
10545 color = "#" + color;
10547 count = count || 1;
10548 duration = o.duration || 1;
10551 var b = this.getBox();
10552 var animFn = function(){
10553 var proxy = this.createProxy({
10556 visbility:"hidden",
10557 position:"absolute",
10558 "z-index":"35000", // yee haw
10559 border:"0px solid " + color
10562 var scale = Roo.isBorderBox ? 2 : 1;
10564 top:{from:b.y, to:b.y - 20},
10565 left:{from:b.x, to:b.x - 20},
10566 borderWidth:{from:0, to:10},
10567 opacity:{from:1, to:0},
10568 height:{from:b.height, to:(b.height + (20*scale))},
10569 width:{from:b.width, to:(b.width + (20*scale))}
10570 }, duration, function(){
10574 animFn.defer((duration/2)*1000, this);
10585 * Creates a pause before any subsequent queued effects begin. If there are
10586 * no effects queued after the pause it will have no effect.
10591 * @param {Number} seconds The length of time to pause (in seconds)
10592 * @return {Roo.Element} The Element
10594 pause : function(seconds){
10595 var el = this.getFxEl();
10598 el.queueFx(o, function(){
10599 setTimeout(function(){
10601 }, seconds * 1000);
10607 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10608 * using the "endOpacity" config option.
10611 // default: fade in from opacity 0 to 100%
10614 // custom: fade in from opacity 0 to 75% over 2 seconds
10615 el.fadeIn({ endOpacity: .75, duration: 2});
10617 // common config options shown with default values
10619 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10624 * @param {Object} options (optional) Object literal with any of the Fx config options
10625 * @return {Roo.Element} The Element
10627 fadeIn : function(o){
10628 var el = this.getFxEl();
10630 el.queueFx(o, function(){
10631 this.setOpacity(0);
10633 this.dom.style.visibility = 'visible';
10634 var to = o.endOpacity || 1;
10635 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10636 o, null, .5, "easeOut", function(){
10638 this.clearOpacity();
10647 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10648 * using the "endOpacity" config option.
10651 // default: fade out from the element's current opacity to 0
10654 // custom: fade out from the element's current opacity to 25% over 2 seconds
10655 el.fadeOut({ endOpacity: .25, duration: 2});
10657 // common config options shown with default values
10659 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10666 * @param {Object} options (optional) Object literal with any of the Fx config options
10667 * @return {Roo.Element} The Element
10669 fadeOut : function(o){
10670 var el = this.getFxEl();
10672 el.queueFx(o, function(){
10673 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10674 o, null, .5, "easeOut", function(){
10675 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10676 this.dom.style.display = "none";
10678 this.dom.style.visibility = "hidden";
10680 this.clearOpacity();
10688 * Animates the transition of an element's dimensions from a starting height/width
10689 * to an ending height/width.
10692 // change height and width to 100x100 pixels
10693 el.scale(100, 100);
10695 // common config options shown with default values. The height and width will default to
10696 // the element's existing values if passed as null.
10699 [element's height], {
10704 * @param {Number} width The new width (pass undefined to keep the original width)
10705 * @param {Number} height The new height (pass undefined to keep the original height)
10706 * @param {Object} options (optional) Object literal with any of the Fx config options
10707 * @return {Roo.Element} The Element
10709 scale : function(w, h, o){
10710 this.shift(Roo.apply({}, o, {
10718 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10719 * Any of these properties not specified in the config object will not be changed. This effect
10720 * requires that at least one new dimension, position or opacity setting must be passed in on
10721 * the config object in order for the function to have any effect.
10724 // slide the element horizontally to x position 200 while changing the height and opacity
10725 el.shift({ x: 200, height: 50, opacity: .8 });
10727 // common config options shown with default values.
10729 width: [element's width],
10730 height: [element's height],
10731 x: [element's x position],
10732 y: [element's y position],
10733 opacity: [element's opacity],
10738 * @param {Object} options Object literal with any of the Fx config options
10739 * @return {Roo.Element} The Element
10741 shift : function(o){
10742 var el = this.getFxEl();
10744 el.queueFx(o, function(){
10745 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10746 if(w !== undefined){
10747 a.width = {to: this.adjustWidth(w)};
10749 if(h !== undefined){
10750 a.height = {to: this.adjustHeight(h)};
10752 if(x !== undefined || y !== undefined){
10754 x !== undefined ? x : this.getX(),
10755 y !== undefined ? y : this.getY()
10758 if(op !== undefined){
10759 a.opacity = {to: op};
10761 if(o.xy !== undefined){
10762 a.points = {to: o.xy};
10764 arguments.callee.anim = this.fxanim(a,
10765 o, 'motion', .35, "easeOut", function(){
10773 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10774 * ending point of the effect.
10777 // default: slide the element downward while fading out
10780 // custom: slide the element out to the right with a 2-second duration
10781 el.ghost('r', { duration: 2 });
10783 // common config options shown with default values
10791 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10792 * @param {Object} options (optional) Object literal with any of the Fx config options
10793 * @return {Roo.Element} The Element
10795 ghost : function(anchor, o){
10796 var el = this.getFxEl();
10799 el.queueFx(o, function(){
10800 anchor = anchor || "b";
10802 // restore values after effect
10803 var r = this.getFxRestore();
10804 var w = this.getWidth(),
10805 h = this.getHeight();
10807 var st = this.dom.style;
10809 var after = function(){
10811 el.setDisplayed(false);
10817 el.setPositioning(r.pos);
10818 st.width = r.width;
10819 st.height = r.height;
10824 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10825 switch(anchor.toLowerCase()){
10852 arguments.callee.anim = this.fxanim(a,
10862 * Ensures that all effects queued after syncFx is called on the element are
10863 * run concurrently. This is the opposite of {@link #sequenceFx}.
10864 * @return {Roo.Element} The Element
10866 syncFx : function(){
10867 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10876 * Ensures that all effects queued after sequenceFx is called on the element are
10877 * run in sequence. This is the opposite of {@link #syncFx}.
10878 * @return {Roo.Element} The Element
10880 sequenceFx : function(){
10881 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10883 concurrent : false,
10890 nextFx : function(){
10891 var ef = this.fxQueue[0];
10898 * Returns true if the element has any effects actively running or queued, else returns false.
10899 * @return {Boolean} True if element has active effects, else false
10901 hasActiveFx : function(){
10902 return this.fxQueue && this.fxQueue[0];
10906 * Stops any running effects and clears the element's internal effects queue if it contains
10907 * any additional effects that haven't started yet.
10908 * @return {Roo.Element} The Element
10910 stopFx : function(){
10911 if(this.hasActiveFx()){
10912 var cur = this.fxQueue[0];
10913 if(cur && cur.anim && cur.anim.isAnimated()){
10914 this.fxQueue = [cur]; // clear out others
10915 cur.anim.stop(true);
10922 beforeFx : function(o){
10923 if(this.hasActiveFx() && !o.concurrent){
10934 * Returns true if the element is currently blocking so that no other effect can be queued
10935 * until this effect is finished, else returns false if blocking is not set. This is commonly
10936 * used to ensure that an effect initiated by a user action runs to completion prior to the
10937 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10938 * @return {Boolean} True if blocking, else false
10940 hasFxBlock : function(){
10941 var q = this.fxQueue;
10942 return q && q[0] && q[0].block;
10946 queueFx : function(o, fn){
10950 if(!this.hasFxBlock()){
10951 Roo.applyIf(o, this.fxDefaults);
10953 var run = this.beforeFx(o);
10954 fn.block = o.block;
10955 this.fxQueue.push(fn);
10967 fxWrap : function(pos, o, vis){
10969 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10972 wrapXY = this.getXY();
10974 var div = document.createElement("div");
10975 div.style.visibility = vis;
10976 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10977 wrap.setPositioning(pos);
10978 if(wrap.getStyle("position") == "static"){
10979 wrap.position("relative");
10981 this.clearPositioning('auto');
10983 wrap.dom.appendChild(this.dom);
10985 wrap.setXY(wrapXY);
10992 fxUnwrap : function(wrap, pos, o){
10993 this.clearPositioning();
10994 this.setPositioning(pos);
10996 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11002 getFxRestore : function(){
11003 var st = this.dom.style;
11004 return {pos: this.getPositioning(), width: st.width, height : st.height};
11008 afterFx : function(o){
11010 this.applyStyles(o.afterStyle);
11013 this.addClass(o.afterCls);
11015 if(o.remove === true){
11018 Roo.callback(o.callback, o.scope, [this]);
11020 this.fxQueue.shift();
11026 getFxEl : function(){ // support for composite element fx
11027 return Roo.get(this.dom);
11031 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11032 animType = animType || 'run';
11034 var anim = Roo.lib.Anim[animType](
11036 (opt.duration || defaultDur) || .35,
11037 (opt.easing || defaultEase) || 'easeOut',
11039 Roo.callback(cb, this);
11048 // backwords compat
11049 Roo.Fx.resize = Roo.Fx.scale;
11051 //When included, Roo.Fx is automatically applied to Element so that all basic
11052 //effects are available directly via the Element API
11053 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11055 * Ext JS Library 1.1.1
11056 * Copyright(c) 2006-2007, Ext JS, LLC.
11058 * Originally Released Under LGPL - original licence link has changed is not relivant.
11061 * <script type="text/javascript">
11066 * @class Roo.CompositeElement
11067 * Standard composite class. Creates a Roo.Element for every element in the collection.
11069 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11070 * actions will be performed on all the elements in this collection.</b>
11072 * All methods return <i>this</i> and can be chained.
11074 var els = Roo.select("#some-el div.some-class", true);
11075 // or select directly from an existing element
11076 var el = Roo.get('some-el');
11077 el.select('div.some-class', true);
11079 els.setWidth(100); // all elements become 100 width
11080 els.hide(true); // all elements fade out and hide
11082 els.setWidth(100).hide(true);
11085 Roo.CompositeElement = function(els){
11086 this.elements = [];
11087 this.addElements(els);
11089 Roo.CompositeElement.prototype = {
11091 addElements : function(els){
11095 if(typeof els == "string"){
11096 els = Roo.Element.selectorFunction(els);
11098 var yels = this.elements;
11099 var index = yels.length-1;
11100 for(var i = 0, len = els.length; i < len; i++) {
11101 yels[++index] = Roo.get(els[i]);
11107 * Clears this composite and adds the elements returned by the passed selector.
11108 * @param {String/Array} els A string CSS selector, an array of elements or an element
11109 * @return {CompositeElement} this
11111 fill : function(els){
11112 this.elements = [];
11118 * Filters this composite to only elements that match the passed selector.
11119 * @param {String} selector A string CSS selector
11120 * @param {Boolean} inverse return inverse filter (not matches)
11121 * @return {CompositeElement} this
11123 filter : function(selector, inverse){
11125 inverse = inverse || false;
11126 this.each(function(el){
11127 var match = inverse ? !el.is(selector) : el.is(selector);
11129 els[els.length] = el.dom;
11136 invoke : function(fn, args){
11137 var els = this.elements;
11138 for(var i = 0, len = els.length; i < len; i++) {
11139 Roo.Element.prototype[fn].apply(els[i], args);
11144 * Adds elements to this composite.
11145 * @param {String/Array} els A string CSS selector, an array of elements or an element
11146 * @return {CompositeElement} this
11148 add : function(els){
11149 if(typeof els == "string"){
11150 this.addElements(Roo.Element.selectorFunction(els));
11151 }else if(els.length !== undefined){
11152 this.addElements(els);
11154 this.addElements([els]);
11159 * Calls the passed function passing (el, this, index) for each element in this composite.
11160 * @param {Function} fn The function to call
11161 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11162 * @return {CompositeElement} this
11164 each : function(fn, scope){
11165 var els = this.elements;
11166 for(var i = 0, len = els.length; i < len; i++){
11167 if(fn.call(scope || els[i], els[i], this, i) === false) {
11175 * Returns the Element object at the specified index
11176 * @param {Number} index
11177 * @return {Roo.Element}
11179 item : function(index){
11180 return this.elements[index] || null;
11184 * Returns the first Element
11185 * @return {Roo.Element}
11187 first : function(){
11188 return this.item(0);
11192 * Returns the last Element
11193 * @return {Roo.Element}
11196 return this.item(this.elements.length-1);
11200 * Returns the number of elements in this composite
11203 getCount : function(){
11204 return this.elements.length;
11208 * Returns true if this composite contains the passed element
11211 contains : function(el){
11212 return this.indexOf(el) !== -1;
11216 * Returns true if this composite contains the passed element
11219 indexOf : function(el){
11220 return this.elements.indexOf(Roo.get(el));
11225 * Removes the specified element(s).
11226 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11227 * or an array of any of those.
11228 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11229 * @return {CompositeElement} this
11231 removeElement : function(el, removeDom){
11232 if(el instanceof Array){
11233 for(var i = 0, len = el.length; i < len; i++){
11234 this.removeElement(el[i]);
11238 var index = typeof el == 'number' ? el : this.indexOf(el);
11241 var d = this.elements[index];
11245 d.parentNode.removeChild(d);
11248 this.elements.splice(index, 1);
11254 * Replaces the specified element with the passed element.
11255 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11257 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11258 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11259 * @return {CompositeElement} this
11261 replaceElement : function(el, replacement, domReplace){
11262 var index = typeof el == 'number' ? el : this.indexOf(el);
11265 this.elements[index].replaceWith(replacement);
11267 this.elements.splice(index, 1, Roo.get(replacement))
11274 * Removes all elements.
11276 clear : function(){
11277 this.elements = [];
11281 Roo.CompositeElement.createCall = function(proto, fnName){
11282 if(!proto[fnName]){
11283 proto[fnName] = function(){
11284 return this.invoke(fnName, arguments);
11288 for(var fnName in Roo.Element.prototype){
11289 if(typeof Roo.Element.prototype[fnName] == "function"){
11290 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11296 * Ext JS Library 1.1.1
11297 * Copyright(c) 2006-2007, Ext JS, LLC.
11299 * Originally Released Under LGPL - original licence link has changed is not relivant.
11302 * <script type="text/javascript">
11306 * @class Roo.CompositeElementLite
11307 * @extends Roo.CompositeElement
11308 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11310 var els = Roo.select("#some-el div.some-class");
11311 // or select directly from an existing element
11312 var el = Roo.get('some-el');
11313 el.select('div.some-class');
11315 els.setWidth(100); // all elements become 100 width
11316 els.hide(true); // all elements fade out and hide
11318 els.setWidth(100).hide(true);
11319 </code></pre><br><br>
11320 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11321 * actions will be performed on all the elements in this collection.</b>
11323 Roo.CompositeElementLite = function(els){
11324 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11325 this.el = new Roo.Element.Flyweight();
11327 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11328 addElements : function(els){
11330 if(els instanceof Array){
11331 this.elements = this.elements.concat(els);
11333 var yels = this.elements;
11334 var index = yels.length-1;
11335 for(var i = 0, len = els.length; i < len; i++) {
11336 yels[++index] = els[i];
11342 invoke : function(fn, args){
11343 var els = this.elements;
11345 for(var i = 0, len = els.length; i < len; i++) {
11347 Roo.Element.prototype[fn].apply(el, args);
11352 * Returns a flyweight Element of the dom element object at the specified index
11353 * @param {Number} index
11354 * @return {Roo.Element}
11356 item : function(index){
11357 if(!this.elements[index]){
11360 this.el.dom = this.elements[index];
11364 // fixes scope with flyweight
11365 addListener : function(eventName, handler, scope, opt){
11366 var els = this.elements;
11367 for(var i = 0, len = els.length; i < len; i++) {
11368 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11374 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11375 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11376 * a reference to the dom node, use el.dom.</b>
11377 * @param {Function} fn The function to call
11378 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11379 * @return {CompositeElement} this
11381 each : function(fn, scope){
11382 var els = this.elements;
11384 for(var i = 0, len = els.length; i < len; i++){
11386 if(fn.call(scope || el, el, this, i) === false){
11393 indexOf : function(el){
11394 return this.elements.indexOf(Roo.getDom(el));
11397 replaceElement : function(el, replacement, domReplace){
11398 var index = typeof el == 'number' ? el : this.indexOf(el);
11400 replacement = Roo.getDom(replacement);
11402 var d = this.elements[index];
11403 d.parentNode.insertBefore(replacement, d);
11404 d.parentNode.removeChild(d);
11406 this.elements.splice(index, 1, replacement);
11411 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11415 * Ext JS Library 1.1.1
11416 * Copyright(c) 2006-2007, Ext JS, LLC.
11418 * Originally Released Under LGPL - original licence link has changed is not relivant.
11421 * <script type="text/javascript">
11427 * @class Roo.data.Connection
11428 * @extends Roo.util.Observable
11429 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11430 * either to a configured URL, or to a URL specified at request time.<br><br>
11432 * Requests made by this class are asynchronous, and will return immediately. No data from
11433 * the server will be available to the statement immediately following the {@link #request} call.
11434 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11436 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11437 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11438 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11439 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11440 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11441 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11442 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11443 * standard DOM methods.
11445 * @param {Object} config a configuration object.
11447 Roo.data.Connection = function(config){
11448 Roo.apply(this, config);
11451 * @event beforerequest
11452 * Fires before a network request is made to retrieve a data object.
11453 * @param {Connection} conn This Connection object.
11454 * @param {Object} options The options config object passed to the {@link #request} method.
11456 "beforerequest" : true,
11458 * @event requestcomplete
11459 * Fires if the request was successfully completed.
11460 * @param {Connection} conn This Connection object.
11461 * @param {Object} response The XHR object containing the response data.
11462 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11463 * @param {Object} options The options config object passed to the {@link #request} method.
11465 "requestcomplete" : true,
11467 * @event requestexception
11468 * Fires if an error HTTP status was returned from the server.
11469 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11470 * @param {Connection} conn This Connection object.
11471 * @param {Object} response The XHR object containing the response data.
11472 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11473 * @param {Object} options The options config object passed to the {@link #request} method.
11475 "requestexception" : true
11477 Roo.data.Connection.superclass.constructor.call(this);
11480 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11482 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11485 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11486 * extra parameters to each request made by this object. (defaults to undefined)
11489 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11490 * to each request made by this object. (defaults to undefined)
11493 * @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)
11496 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11500 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11506 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11509 disableCaching: true,
11512 * Sends an HTTP request to a remote server.
11513 * @param {Object} options An object which may contain the following properties:<ul>
11514 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11515 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11516 * request, a url encoded string or a function to call to get either.</li>
11517 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11518 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11519 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11520 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11521 * <li>options {Object} The parameter to the request call.</li>
11522 * <li>success {Boolean} True if the request succeeded.</li>
11523 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11525 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11526 * The callback is passed the following parameters:<ul>
11527 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11528 * <li>options {Object} The parameter to the request call.</li>
11530 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11531 * The callback is passed the following parameters:<ul>
11532 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11533 * <li>options {Object} The parameter to the request call.</li>
11535 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11536 * for the callback function. Defaults to the browser window.</li>
11537 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11538 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11539 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11540 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11541 * params for the post data. Any params will be appended to the URL.</li>
11542 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11544 * @return {Number} transactionId
11546 request : function(o){
11547 if(this.fireEvent("beforerequest", this, o) !== false){
11550 if(typeof p == "function"){
11551 p = p.call(o.scope||window, o);
11553 if(typeof p == "object"){
11554 p = Roo.urlEncode(o.params);
11556 if(this.extraParams){
11557 var extras = Roo.urlEncode(this.extraParams);
11558 p = p ? (p + '&' + extras) : extras;
11561 var url = o.url || this.url;
11562 if(typeof url == 'function'){
11563 url = url.call(o.scope||window, o);
11567 var form = Roo.getDom(o.form);
11568 url = url || form.action;
11570 var enctype = form.getAttribute("enctype");
11571 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11572 return this.doFormUpload(o, p, url);
11574 var f = Roo.lib.Ajax.serializeForm(form);
11575 p = p ? (p + '&' + f) : f;
11578 var hs = o.headers;
11579 if(this.defaultHeaders){
11580 hs = Roo.apply(hs || {}, this.defaultHeaders);
11587 success: this.handleResponse,
11588 failure: this.handleFailure,
11590 argument: {options: o},
11591 timeout : o.timeout || this.timeout
11594 var method = o.method||this.method||(p ? "POST" : "GET");
11596 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11597 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11600 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11604 }else if(this.autoAbort !== false){
11608 if((method == 'GET' && p) || o.xmlData){
11609 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11612 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11613 return this.transId;
11615 Roo.callback(o.callback, o.scope, [o, null, null]);
11621 * Determine whether this object has a request outstanding.
11622 * @param {Number} transactionId (Optional) defaults to the last transaction
11623 * @return {Boolean} True if there is an outstanding request.
11625 isLoading : function(transId){
11627 return Roo.lib.Ajax.isCallInProgress(transId);
11629 return this.transId ? true : false;
11634 * Aborts any outstanding request.
11635 * @param {Number} transactionId (Optional) defaults to the last transaction
11637 abort : function(transId){
11638 if(transId || this.isLoading()){
11639 Roo.lib.Ajax.abort(transId || this.transId);
11644 handleResponse : function(response){
11645 this.transId = false;
11646 var options = response.argument.options;
11647 response.argument = options ? options.argument : null;
11648 this.fireEvent("requestcomplete", this, response, options);
11649 Roo.callback(options.success, options.scope, [response, options]);
11650 Roo.callback(options.callback, options.scope, [options, true, response]);
11654 handleFailure : function(response, e){
11655 this.transId = false;
11656 var options = response.argument.options;
11657 response.argument = options ? options.argument : null;
11658 this.fireEvent("requestexception", this, response, options, e);
11659 Roo.callback(options.failure, options.scope, [response, options]);
11660 Roo.callback(options.callback, options.scope, [options, false, response]);
11664 doFormUpload : function(o, ps, url){
11666 var frame = document.createElement('iframe');
11669 frame.className = 'x-hidden';
11671 frame.src = Roo.SSL_SECURE_URL;
11673 document.body.appendChild(frame);
11676 document.frames[id].name = id;
11679 var form = Roo.getDom(o.form);
11681 form.method = 'POST';
11682 form.enctype = form.encoding = 'multipart/form-data';
11688 if(ps){ // add dynamic params
11690 ps = Roo.urlDecode(ps, false);
11692 if(ps.hasOwnProperty(k)){
11693 hd = document.createElement('input');
11694 hd.type = 'hidden';
11697 form.appendChild(hd);
11704 var r = { // bogus response object
11709 r.argument = o ? o.argument : null;
11714 doc = frame.contentWindow.document;
11716 doc = (frame.contentDocument || window.frames[id].document);
11718 if(doc && doc.body){
11719 r.responseText = doc.body.innerHTML;
11721 if(doc && doc.XMLDocument){
11722 r.responseXML = doc.XMLDocument;
11724 r.responseXML = doc;
11731 Roo.EventManager.removeListener(frame, 'load', cb, this);
11733 this.fireEvent("requestcomplete", this, r, o);
11734 Roo.callback(o.success, o.scope, [r, o]);
11735 Roo.callback(o.callback, o.scope, [o, true, r]);
11737 setTimeout(function(){document.body.removeChild(frame);}, 100);
11740 Roo.EventManager.on(frame, 'load', cb, this);
11743 if(hiddens){ // remove dynamic params
11744 for(var i = 0, len = hiddens.length; i < len; i++){
11745 form.removeChild(hiddens[i]);
11752 * Ext JS Library 1.1.1
11753 * Copyright(c) 2006-2007, Ext JS, LLC.
11755 * Originally Released Under LGPL - original licence link has changed is not relivant.
11758 * <script type="text/javascript">
11762 * Global Ajax request class.
11765 * @extends Roo.data.Connection
11768 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11769 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11770 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11771 * @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)
11772 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11773 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11774 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11776 Roo.Ajax = new Roo.data.Connection({
11785 * Serialize the passed form into a url encoded string
11787 * @param {String/HTMLElement} form
11790 serializeForm : function(form){
11791 return Roo.lib.Ajax.serializeForm(form);
11795 * Ext JS Library 1.1.1
11796 * Copyright(c) 2006-2007, Ext JS, LLC.
11798 * Originally Released Under LGPL - original licence link has changed is not relivant.
11801 * <script type="text/javascript">
11806 * @class Roo.UpdateManager
11807 * @extends Roo.util.Observable
11808 * Provides AJAX-style update for Element object.<br><br>
11811 * // Get it from a Roo.Element object
11812 * var el = Roo.get("foo");
11813 * var mgr = el.getUpdateManager();
11814 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11816 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11818 * // or directly (returns the same UpdateManager instance)
11819 * var mgr = new Roo.UpdateManager("myElementId");
11820 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11821 * mgr.on("update", myFcnNeedsToKnow);
11823 // short handed call directly from the element object
11824 Roo.get("foo").load({
11828 text: "Loading Foo..."
11832 * Create new UpdateManager directly.
11833 * @param {String/HTMLElement/Roo.Element} el The element to update
11834 * @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).
11836 Roo.UpdateManager = function(el, forceNew){
11838 if(!forceNew && el.updateManager){
11839 return el.updateManager;
11842 * The Element object
11843 * @type Roo.Element
11847 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11850 this.defaultUrl = null;
11854 * @event beforeupdate
11855 * Fired before an update is made, return false from your handler and the update is cancelled.
11856 * @param {Roo.Element} el
11857 * @param {String/Object/Function} url
11858 * @param {String/Object} params
11860 "beforeupdate": true,
11863 * Fired after successful update is made.
11864 * @param {Roo.Element} el
11865 * @param {Object} oResponseObject The response Object
11870 * Fired on update failure.
11871 * @param {Roo.Element} el
11872 * @param {Object} oResponseObject The response Object
11876 var d = Roo.UpdateManager.defaults;
11878 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11881 this.sslBlankUrl = d.sslBlankUrl;
11883 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11886 this.disableCaching = d.disableCaching;
11888 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11891 this.indicatorText = d.indicatorText;
11893 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11896 this.showLoadIndicator = d.showLoadIndicator;
11898 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11901 this.timeout = d.timeout;
11904 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11907 this.loadScripts = d.loadScripts;
11910 * Transaction object of current executing transaction
11912 this.transaction = null;
11917 this.autoRefreshProcId = null;
11919 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11922 this.refreshDelegate = this.refresh.createDelegate(this);
11924 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11927 this.updateDelegate = this.update.createDelegate(this);
11929 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11932 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11936 this.successDelegate = this.processSuccess.createDelegate(this);
11940 this.failureDelegate = this.processFailure.createDelegate(this);
11942 if(!this.renderer){
11944 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11946 this.renderer = new Roo.UpdateManager.BasicRenderer();
11949 Roo.UpdateManager.superclass.constructor.call(this);
11952 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11954 * Get the Element this UpdateManager is bound to
11955 * @return {Roo.Element} The element
11957 getEl : function(){
11961 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11962 * @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:
11965 url: "your-url.php",<br/>
11966 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11967 callback: yourFunction,<br/>
11968 scope: yourObject, //(optional scope) <br/>
11969 discardUrl: false, <br/>
11970 nocache: false,<br/>
11971 text: "Loading...",<br/>
11973 scripts: false<br/>
11976 * The only required property is url. The optional properties nocache, text and scripts
11977 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11978 * @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}
11979 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11980 * @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.
11982 update : function(url, params, callback, discardUrl){
11983 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11984 var method = this.method,
11986 if(typeof url == "object"){ // must be config object
11989 params = params || cfg.params;
11990 callback = callback || cfg.callback;
11991 discardUrl = discardUrl || cfg.discardUrl;
11992 if(callback && cfg.scope){
11993 callback = callback.createDelegate(cfg.scope);
11995 if(typeof cfg.method != "undefined"){method = cfg.method;};
11996 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11997 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11998 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11999 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12001 this.showLoading();
12003 this.defaultUrl = url;
12005 if(typeof url == "function"){
12006 url = url.call(this);
12009 method = method || (params ? "POST" : "GET");
12010 if(method == "GET"){
12011 url = this.prepareUrl(url);
12014 var o = Roo.apply(cfg ||{}, {
12017 success: this.successDelegate,
12018 failure: this.failureDelegate,
12019 callback: undefined,
12020 timeout: (this.timeout*1000),
12021 argument: {"url": url, "form": null, "callback": callback, "params": params}
12023 Roo.log("updated manager called with timeout of " + o.timeout);
12024 this.transaction = Roo.Ajax.request(o);
12029 * 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.
12030 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12031 * @param {String/HTMLElement} form The form Id or form element
12032 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12033 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12034 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12036 formUpdate : function(form, url, reset, callback){
12037 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12038 if(typeof url == "function"){
12039 url = url.call(this);
12041 form = Roo.getDom(form);
12042 this.transaction = Roo.Ajax.request({
12045 success: this.successDelegate,
12046 failure: this.failureDelegate,
12047 timeout: (this.timeout*1000),
12048 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12050 this.showLoading.defer(1, this);
12055 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12056 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12058 refresh : function(callback){
12059 if(this.defaultUrl == null){
12062 this.update(this.defaultUrl, null, callback, true);
12066 * Set this element to auto refresh.
12067 * @param {Number} interval How often to update (in seconds).
12068 * @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)
12069 * @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}
12070 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12071 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12073 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12075 this.update(url || this.defaultUrl, params, callback, true);
12077 if(this.autoRefreshProcId){
12078 clearInterval(this.autoRefreshProcId);
12080 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12084 * Stop auto refresh on this element.
12086 stopAutoRefresh : function(){
12087 if(this.autoRefreshProcId){
12088 clearInterval(this.autoRefreshProcId);
12089 delete this.autoRefreshProcId;
12093 isAutoRefreshing : function(){
12094 return this.autoRefreshProcId ? true : false;
12097 * Called to update the element to "Loading" state. Override to perform custom action.
12099 showLoading : function(){
12100 if(this.showLoadIndicator){
12101 this.el.update(this.indicatorText);
12106 * Adds unique parameter to query string if disableCaching = true
12109 prepareUrl : function(url){
12110 if(this.disableCaching){
12111 var append = "_dc=" + (new Date().getTime());
12112 if(url.indexOf("?") !== -1){
12113 url += "&" + append;
12115 url += "?" + append;
12124 processSuccess : function(response){
12125 this.transaction = null;
12126 if(response.argument.form && response.argument.reset){
12127 try{ // put in try/catch since some older FF releases had problems with this
12128 response.argument.form.reset();
12131 if(this.loadScripts){
12132 this.renderer.render(this.el, response, this,
12133 this.updateComplete.createDelegate(this, [response]));
12135 this.renderer.render(this.el, response, this);
12136 this.updateComplete(response);
12140 updateComplete : function(response){
12141 this.fireEvent("update", this.el, response);
12142 if(typeof response.argument.callback == "function"){
12143 response.argument.callback(this.el, true, response);
12150 processFailure : function(response){
12151 this.transaction = null;
12152 this.fireEvent("failure", this.el, response);
12153 if(typeof response.argument.callback == "function"){
12154 response.argument.callback(this.el, false, response);
12159 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12160 * @param {Object} renderer The object implementing the render() method
12162 setRenderer : function(renderer){
12163 this.renderer = renderer;
12166 getRenderer : function(){
12167 return this.renderer;
12171 * Set the defaultUrl used for updates
12172 * @param {String/Function} defaultUrl The url or a function to call to get the url
12174 setDefaultUrl : function(defaultUrl){
12175 this.defaultUrl = defaultUrl;
12179 * Aborts the executing transaction
12181 abort : function(){
12182 if(this.transaction){
12183 Roo.Ajax.abort(this.transaction);
12188 * Returns true if an update is in progress
12189 * @return {Boolean}
12191 isUpdating : function(){
12192 if(this.transaction){
12193 return Roo.Ajax.isLoading(this.transaction);
12200 * @class Roo.UpdateManager.defaults
12201 * @static (not really - but it helps the doc tool)
12202 * The defaults collection enables customizing the default properties of UpdateManager
12204 Roo.UpdateManager.defaults = {
12206 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12212 * True to process scripts by default (Defaults to false).
12215 loadScripts : false,
12218 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12221 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12223 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12226 disableCaching : false,
12228 * Whether to show indicatorText when loading (Defaults to true).
12231 showLoadIndicator : true,
12233 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12236 indicatorText : '<div class="loading-indicator">Loading...</div>'
12240 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12242 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12243 * @param {String/HTMLElement/Roo.Element} el The element to update
12244 * @param {String} url The url
12245 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12246 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12249 * @member Roo.UpdateManager
12251 Roo.UpdateManager.updateElement = function(el, url, params, options){
12252 var um = Roo.get(el, true).getUpdateManager();
12253 Roo.apply(um, options);
12254 um.update(url, params, options ? options.callback : null);
12256 // alias for backwards compat
12257 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12259 * @class Roo.UpdateManager.BasicRenderer
12260 * Default Content renderer. Updates the elements innerHTML with the responseText.
12262 Roo.UpdateManager.BasicRenderer = function(){};
12264 Roo.UpdateManager.BasicRenderer.prototype = {
12266 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12267 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12268 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12269 * @param {Roo.Element} el The element being rendered
12270 * @param {Object} response The YUI Connect response object
12271 * @param {UpdateManager} updateManager The calling update manager
12272 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12274 render : function(el, response, updateManager, callback){
12275 el.update(response.responseText, updateManager.loadScripts, callback);
12281 * (c)) Alan Knowles
12287 * @class Roo.DomTemplate
12288 * @extends Roo.Template
12289 * An effort at a dom based template engine..
12291 * Similar to XTemplate, except it uses dom parsing to create the template..
12293 * Supported features:
12298 {a_variable} - output encoded.
12299 {a_variable.format:("Y-m-d")} - call a method on the variable
12300 {a_variable:raw} - unencoded output
12301 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12302 {a_variable:this.method_on_template(...)} - call a method on the template object.
12307 <div roo-for="a_variable or condition.."></div>
12308 <div roo-if="a_variable or condition"></div>
12309 <div roo-exec="some javascript"></div>
12310 <div roo-name="named_template"></div>
12315 Roo.DomTemplate = function()
12317 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12324 Roo.extend(Roo.DomTemplate, Roo.Template, {
12326 * id counter for sub templates.
12330 * flag to indicate if dom parser is inside a pre,
12331 * it will strip whitespace if not.
12336 * The various sub templates
12344 * basic tag replacing syntax
12347 * // you can fake an object call by doing this
12351 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12352 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12354 iterChild : function (node, method) {
12356 var oldPre = this.inPre;
12357 if (node.tagName == 'PRE') {
12360 for( var i = 0; i < node.childNodes.length; i++) {
12361 method.call(this, node.childNodes[i]);
12363 this.inPre = oldPre;
12369 * compile the template
12371 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12374 compile: function()
12378 // covert the html into DOM...
12382 doc = document.implementation.createHTMLDocument("");
12383 doc.documentElement.innerHTML = this.html ;
12384 div = doc.documentElement;
12386 // old IE... - nasty -- it causes all sorts of issues.. with
12387 // images getting pulled from server..
12388 div = document.createElement('div');
12389 div.innerHTML = this.html;
12391 //doc.documentElement.innerHTML = htmlBody
12397 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12399 var tpls = this.tpls;
12401 // create a top level template from the snippet..
12403 //Roo.log(div.innerHTML);
12410 body : div.innerHTML,
12423 Roo.each(tpls, function(tp){
12424 this.compileTpl(tp);
12425 this.tpls[tp.id] = tp;
12428 this.master = tpls[0];
12434 compileNode : function(node, istop) {
12439 // skip anything not a tag..
12440 if (node.nodeType != 1) {
12441 if (node.nodeType == 3 && !this.inPre) {
12442 // reduce white space..
12443 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12466 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12467 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12468 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12469 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12475 // just itterate children..
12476 this.iterChild(node,this.compileNode);
12479 tpl.uid = this.id++;
12480 tpl.value = node.getAttribute('roo-' + tpl.attr);
12481 node.removeAttribute('roo-'+ tpl.attr);
12482 if (tpl.attr != 'name') {
12483 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12484 node.parentNode.replaceChild(placeholder, node);
12487 var placeholder = document.createElement('span');
12488 placeholder.className = 'roo-tpl-' + tpl.value;
12489 node.parentNode.replaceChild(placeholder, node);
12492 // parent now sees '{domtplXXXX}
12493 this.iterChild(node,this.compileNode);
12495 // we should now have node body...
12496 var div = document.createElement('div');
12497 div.appendChild(node);
12499 // this has the unfortunate side effect of converting tagged attributes
12500 // eg. href="{...}" into %7C...%7D
12501 // this has been fixed by searching for those combo's although it's a bit hacky..
12504 tpl.body = div.innerHTML;
12511 switch (tpl.value) {
12512 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12513 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12514 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12519 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12523 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12527 tpl.id = tpl.value; // replace non characters???
12533 this.tpls.push(tpl);
12543 * Compile a segment of the template into a 'sub-template'
12549 compileTpl : function(tpl)
12551 var fm = Roo.util.Format;
12552 var useF = this.disableFormats !== true;
12554 var sep = Roo.isGecko ? "+\n" : ",\n";
12556 var undef = function(str) {
12557 Roo.debug && Roo.log("Property not found :" + str);
12561 //Roo.log(tpl.body);
12565 var fn = function(m, lbrace, name, format, args)
12568 //Roo.log(arguments);
12569 args = args ? args.replace(/\\'/g,"'") : args;
12570 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12571 if (typeof(format) == 'undefined') {
12572 format = 'htmlEncode';
12574 if (format == 'raw' ) {
12578 if(name.substr(0, 6) == 'domtpl'){
12579 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12582 // build an array of options to determine if value is undefined..
12584 // basically get 'xxxx.yyyy' then do
12585 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12586 // (function () { Roo.log("Property not found"); return ''; })() :
12591 Roo.each(name.split('.'), function(st) {
12592 lookfor += (lookfor.length ? '.': '') + st;
12593 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12596 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12599 if(format && useF){
12601 args = args ? ',' + args : "";
12603 if(format.substr(0, 5) != "this."){
12604 format = "fm." + format + '(';
12606 format = 'this.call("'+ format.substr(5) + '", ';
12610 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12613 if (args && args.length) {
12614 // called with xxyx.yuu:(test,test)
12616 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12618 // raw.. - :raw modifier..
12619 return "'"+ sep + udef_st + name + ")"+sep+"'";
12623 // branched to use + in gecko and [].join() in others
12625 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12626 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12629 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12630 body.push(tpl.body.replace(/(\r\n|\n)/g,
12631 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12632 body.push("'].join('');};};");
12633 body = body.join('');
12636 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12638 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12645 * same as applyTemplate, except it's done to one of the subTemplates
12646 * when using named templates, you can do:
12648 * var str = pl.applySubTemplate('your-name', values);
12651 * @param {Number} id of the template
12652 * @param {Object} values to apply to template
12653 * @param {Object} parent (normaly the instance of this object)
12655 applySubTemplate : function(id, values, parent)
12659 var t = this.tpls[id];
12663 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12664 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12668 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12675 if(t.execCall && t.execCall.call(this, values, parent)){
12679 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12685 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12686 parent = t.target ? values : parent;
12687 if(t.forCall && vs instanceof Array){
12689 for(var i = 0, len = vs.length; i < len; i++){
12691 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12693 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12695 //Roo.log(t.compiled);
12699 return buf.join('');
12702 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12707 return t.compiled.call(this, vs, parent);
12709 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12711 //Roo.log(t.compiled);
12719 applyTemplate : function(values){
12720 return this.master.compiled.call(this, values, {});
12721 //var s = this.subs;
12724 apply : function(){
12725 return this.applyTemplate.apply(this, arguments);
12730 Roo.DomTemplate.from = function(el){
12731 el = Roo.getDom(el);
12732 return new Roo.Domtemplate(el.value || el.innerHTML);
12735 * Ext JS Library 1.1.1
12736 * Copyright(c) 2006-2007, Ext JS, LLC.
12738 * Originally Released Under LGPL - original licence link has changed is not relivant.
12741 * <script type="text/javascript">
12745 * @class Roo.util.DelayedTask
12746 * Provides a convenient method of performing setTimeout where a new
12747 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12748 * You can use this class to buffer
12749 * the keypress events for a certain number of milliseconds, and perform only if they stop
12750 * for that amount of time.
12751 * @constructor The parameters to this constructor serve as defaults and are not required.
12752 * @param {Function} fn (optional) The default function to timeout
12753 * @param {Object} scope (optional) The default scope of that timeout
12754 * @param {Array} args (optional) The default Array of arguments
12756 Roo.util.DelayedTask = function(fn, scope, args){
12757 var id = null, d, t;
12759 var call = function(){
12760 var now = new Date().getTime();
12764 fn.apply(scope, args || []);
12768 * Cancels any pending timeout and queues a new one
12769 * @param {Number} delay The milliseconds to delay
12770 * @param {Function} newFn (optional) Overrides function passed to constructor
12771 * @param {Object} newScope (optional) Overrides scope passed to constructor
12772 * @param {Array} newArgs (optional) Overrides args passed to constructor
12774 this.delay = function(delay, newFn, newScope, newArgs){
12775 if(id && delay != d){
12779 t = new Date().getTime();
12781 scope = newScope || scope;
12782 args = newArgs || args;
12784 id = setInterval(call, d);
12789 * Cancel the last queued timeout
12791 this.cancel = function(){
12799 * Ext JS Library 1.1.1
12800 * Copyright(c) 2006-2007, Ext JS, LLC.
12802 * Originally Released Under LGPL - original licence link has changed is not relivant.
12805 * <script type="text/javascript">
12809 Roo.util.TaskRunner = function(interval){
12810 interval = interval || 10;
12811 var tasks = [], removeQueue = [];
12813 var running = false;
12815 var stopThread = function(){
12821 var startThread = function(){
12824 id = setInterval(runTasks, interval);
12828 var removeTask = function(task){
12829 removeQueue.push(task);
12835 var runTasks = function(){
12836 if(removeQueue.length > 0){
12837 for(var i = 0, len = removeQueue.length; i < len; i++){
12838 tasks.remove(removeQueue[i]);
12841 if(tasks.length < 1){
12846 var now = new Date().getTime();
12847 for(var i = 0, len = tasks.length; i < len; ++i){
12849 var itime = now - t.taskRunTime;
12850 if(t.interval <= itime){
12851 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12852 t.taskRunTime = now;
12853 if(rt === false || t.taskRunCount === t.repeat){
12858 if(t.duration && t.duration <= (now - t.taskStartTime)){
12865 * Queues a new task.
12866 * @param {Object} task
12868 this.start = function(task){
12870 task.taskStartTime = new Date().getTime();
12871 task.taskRunTime = 0;
12872 task.taskRunCount = 0;
12877 this.stop = function(task){
12882 this.stopAll = function(){
12884 for(var i = 0, len = tasks.length; i < len; i++){
12885 if(tasks[i].onStop){
12894 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12896 * Ext JS Library 1.1.1
12897 * Copyright(c) 2006-2007, Ext JS, LLC.
12899 * Originally Released Under LGPL - original licence link has changed is not relivant.
12902 * <script type="text/javascript">
12907 * @class Roo.util.MixedCollection
12908 * @extends Roo.util.Observable
12909 * A Collection class that maintains both numeric indexes and keys and exposes events.
12911 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12912 * collection (defaults to false)
12913 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12914 * and return the key value for that item. This is used when available to look up the key on items that
12915 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12916 * equivalent to providing an implementation for the {@link #getKey} method.
12918 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12926 * Fires when the collection is cleared.
12931 * Fires when an item is added to the collection.
12932 * @param {Number} index The index at which the item was added.
12933 * @param {Object} o The item added.
12934 * @param {String} key The key associated with the added item.
12939 * Fires when an item is replaced in the collection.
12940 * @param {String} key he key associated with the new added.
12941 * @param {Object} old The item being replaced.
12942 * @param {Object} new The new item.
12947 * Fires when an item is removed from the collection.
12948 * @param {Object} o The item being removed.
12949 * @param {String} key (optional) The key associated with the removed item.
12954 this.allowFunctions = allowFunctions === true;
12956 this.getKey = keyFn;
12958 Roo.util.MixedCollection.superclass.constructor.call(this);
12961 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12962 allowFunctions : false,
12965 * Adds an item to the collection.
12966 * @param {String} key The key to associate with the item
12967 * @param {Object} o The item to add.
12968 * @return {Object} The item added.
12970 add : function(key, o){
12971 if(arguments.length == 1){
12973 key = this.getKey(o);
12975 if(typeof key == "undefined" || key === null){
12977 this.items.push(o);
12978 this.keys.push(null);
12980 var old = this.map[key];
12982 return this.replace(key, o);
12985 this.items.push(o);
12987 this.keys.push(key);
12989 this.fireEvent("add", this.length-1, o, key);
12994 * MixedCollection has a generic way to fetch keys if you implement getKey.
12997 var mc = new Roo.util.MixedCollection();
12998 mc.add(someEl.dom.id, someEl);
12999 mc.add(otherEl.dom.id, otherEl);
13003 var mc = new Roo.util.MixedCollection();
13004 mc.getKey = function(el){
13010 // or via the constructor
13011 var mc = new Roo.util.MixedCollection(false, function(el){
13017 * @param o {Object} The item for which to find the key.
13018 * @return {Object} The key for the passed item.
13020 getKey : function(o){
13025 * Replaces an item in the collection.
13026 * @param {String} key The key associated with the item to replace, or the item to replace.
13027 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13028 * @return {Object} The new item.
13030 replace : function(key, o){
13031 if(arguments.length == 1){
13033 key = this.getKey(o);
13035 var old = this.item(key);
13036 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13037 return this.add(key, o);
13039 var index = this.indexOfKey(key);
13040 this.items[index] = o;
13042 this.fireEvent("replace", key, old, o);
13047 * Adds all elements of an Array or an Object to the collection.
13048 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13049 * an Array of values, each of which are added to the collection.
13051 addAll : function(objs){
13052 if(arguments.length > 1 || objs instanceof Array){
13053 var args = arguments.length > 1 ? arguments : objs;
13054 for(var i = 0, len = args.length; i < len; i++){
13058 for(var key in objs){
13059 if(this.allowFunctions || typeof objs[key] != "function"){
13060 this.add(key, objs[key]);
13067 * Executes the specified function once for every item in the collection, passing each
13068 * item as the first and only parameter. returning false from the function will stop the iteration.
13069 * @param {Function} fn The function to execute for each item.
13070 * @param {Object} scope (optional) The scope in which to execute the function.
13072 each : function(fn, scope){
13073 var items = [].concat(this.items); // each safe for removal
13074 for(var i = 0, len = items.length; i < len; i++){
13075 if(fn.call(scope || items[i], items[i], i, len) === false){
13082 * Executes the specified function once for every key in the collection, passing each
13083 * key, and its associated item as the first two parameters.
13084 * @param {Function} fn The function to execute for each item.
13085 * @param {Object} scope (optional) The scope in which to execute the function.
13087 eachKey : function(fn, scope){
13088 for(var i = 0, len = this.keys.length; i < len; i++){
13089 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13094 * Returns the first item in the collection which elicits a true return value from the
13095 * passed selection function.
13096 * @param {Function} fn The selection function to execute for each item.
13097 * @param {Object} scope (optional) The scope in which to execute the function.
13098 * @return {Object} The first item in the collection which returned true from the selection function.
13100 find : function(fn, scope){
13101 for(var i = 0, len = this.items.length; i < len; i++){
13102 if(fn.call(scope || window, this.items[i], this.keys[i])){
13103 return this.items[i];
13110 * Inserts an item at the specified index in the collection.
13111 * @param {Number} index The index to insert the item at.
13112 * @param {String} key The key to associate with the new item, or the item itself.
13113 * @param {Object} o (optional) If the second parameter was a key, the new item.
13114 * @return {Object} The item inserted.
13116 insert : function(index, key, o){
13117 if(arguments.length == 2){
13119 key = this.getKey(o);
13121 if(index >= this.length){
13122 return this.add(key, o);
13125 this.items.splice(index, 0, o);
13126 if(typeof key != "undefined" && key != null){
13129 this.keys.splice(index, 0, key);
13130 this.fireEvent("add", index, o, key);
13135 * Removed an item from the collection.
13136 * @param {Object} o The item to remove.
13137 * @return {Object} The item removed.
13139 remove : function(o){
13140 return this.removeAt(this.indexOf(o));
13144 * Remove an item from a specified index in the collection.
13145 * @param {Number} index The index within the collection of the item to remove.
13147 removeAt : function(index){
13148 if(index < this.length && index >= 0){
13150 var o = this.items[index];
13151 this.items.splice(index, 1);
13152 var key = this.keys[index];
13153 if(typeof key != "undefined"){
13154 delete this.map[key];
13156 this.keys.splice(index, 1);
13157 this.fireEvent("remove", o, key);
13162 * Removed an item associated with the passed key fom the collection.
13163 * @param {String} key The key of the item to remove.
13165 removeKey : function(key){
13166 return this.removeAt(this.indexOfKey(key));
13170 * Returns the number of items in the collection.
13171 * @return {Number} the number of items in the collection.
13173 getCount : function(){
13174 return this.length;
13178 * Returns index within the collection of the passed Object.
13179 * @param {Object} o The item to find the index of.
13180 * @return {Number} index of the item.
13182 indexOf : function(o){
13183 if(!this.items.indexOf){
13184 for(var i = 0, len = this.items.length; i < len; i++){
13185 if(this.items[i] == o) {
13191 return this.items.indexOf(o);
13196 * Returns index within the collection of the passed key.
13197 * @param {String} key The key to find the index of.
13198 * @return {Number} index of the key.
13200 indexOfKey : function(key){
13201 if(!this.keys.indexOf){
13202 for(var i = 0, len = this.keys.length; i < len; i++){
13203 if(this.keys[i] == key) {
13209 return this.keys.indexOf(key);
13214 * Returns the item associated with the passed key OR index. Key has priority over index.
13215 * @param {String/Number} key The key or index of the item.
13216 * @return {Object} The item associated with the passed key.
13218 item : function(key){
13219 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13220 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13224 * Returns the item at the specified index.
13225 * @param {Number} index The index of the item.
13228 itemAt : function(index){
13229 return this.items[index];
13233 * Returns the item associated with the passed key.
13234 * @param {String/Number} key The key of the item.
13235 * @return {Object} The item associated with the passed key.
13237 key : function(key){
13238 return this.map[key];
13242 * Returns true if the collection contains the passed Object as an item.
13243 * @param {Object} o The Object to look for in the collection.
13244 * @return {Boolean} True if the collection contains the Object as an item.
13246 contains : function(o){
13247 return this.indexOf(o) != -1;
13251 * Returns true if the collection contains the passed Object as a key.
13252 * @param {String} key The key to look for in the collection.
13253 * @return {Boolean} True if the collection contains the Object as a key.
13255 containsKey : function(key){
13256 return typeof this.map[key] != "undefined";
13260 * Removes all items from the collection.
13262 clear : function(){
13267 this.fireEvent("clear");
13271 * Returns the first item in the collection.
13272 * @return {Object} the first item in the collection..
13274 first : function(){
13275 return this.items[0];
13279 * Returns the last item in the collection.
13280 * @return {Object} the last item in the collection..
13283 return this.items[this.length-1];
13286 _sort : function(property, dir, fn){
13287 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13288 fn = fn || function(a, b){
13291 var c = [], k = this.keys, items = this.items;
13292 for(var i = 0, len = items.length; i < len; i++){
13293 c[c.length] = {key: k[i], value: items[i], index: i};
13295 c.sort(function(a, b){
13296 var v = fn(a[property], b[property]) * dsc;
13298 v = (a.index < b.index ? -1 : 1);
13302 for(var i = 0, len = c.length; i < len; i++){
13303 items[i] = c[i].value;
13306 this.fireEvent("sort", this);
13310 * Sorts this collection with the passed comparison function
13311 * @param {String} direction (optional) "ASC" or "DESC"
13312 * @param {Function} fn (optional) comparison function
13314 sort : function(dir, fn){
13315 this._sort("value", dir, fn);
13319 * Sorts this collection by keys
13320 * @param {String} direction (optional) "ASC" or "DESC"
13321 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13323 keySort : function(dir, fn){
13324 this._sort("key", dir, fn || function(a, b){
13325 return String(a).toUpperCase()-String(b).toUpperCase();
13330 * Returns a range of items in this collection
13331 * @param {Number} startIndex (optional) defaults to 0
13332 * @param {Number} endIndex (optional) default to the last item
13333 * @return {Array} An array of items
13335 getRange : function(start, end){
13336 var items = this.items;
13337 if(items.length < 1){
13340 start = start || 0;
13341 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13344 for(var i = start; i <= end; i++) {
13345 r[r.length] = items[i];
13348 for(var i = start; i >= end; i--) {
13349 r[r.length] = items[i];
13356 * Filter the <i>objects</i> in this collection by a specific property.
13357 * Returns a new collection that has been filtered.
13358 * @param {String} property A property on your objects
13359 * @param {String/RegExp} value Either string that the property values
13360 * should start with or a RegExp to test against the property
13361 * @return {MixedCollection} The new filtered collection
13363 filter : function(property, value){
13364 if(!value.exec){ // not a regex
13365 value = String(value);
13366 if(value.length == 0){
13367 return this.clone();
13369 value = new RegExp("^" + Roo.escapeRe(value), "i");
13371 return this.filterBy(function(o){
13372 return o && value.test(o[property]);
13377 * Filter by a function. * Returns a new collection that has been filtered.
13378 * The passed function will be called with each
13379 * object in the collection. If the function returns true, the value is included
13380 * otherwise it is filtered.
13381 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13382 * @param {Object} scope (optional) The scope of the function (defaults to this)
13383 * @return {MixedCollection} The new filtered collection
13385 filterBy : function(fn, scope){
13386 var r = new Roo.util.MixedCollection();
13387 r.getKey = this.getKey;
13388 var k = this.keys, it = this.items;
13389 for(var i = 0, len = it.length; i < len; i++){
13390 if(fn.call(scope||this, it[i], k[i])){
13391 r.add(k[i], it[i]);
13398 * Creates a duplicate of this collection
13399 * @return {MixedCollection}
13401 clone : function(){
13402 var r = new Roo.util.MixedCollection();
13403 var k = this.keys, it = this.items;
13404 for(var i = 0, len = it.length; i < len; i++){
13405 r.add(k[i], it[i]);
13407 r.getKey = this.getKey;
13412 * Returns the item associated with the passed key or index.
13414 * @param {String/Number} key The key or index of the item.
13415 * @return {Object} The item associated with the passed key.
13417 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13419 * Ext JS Library 1.1.1
13420 * Copyright(c) 2006-2007, Ext JS, LLC.
13422 * Originally Released Under LGPL - original licence link has changed is not relivant.
13425 * <script type="text/javascript">
13428 * @class Roo.util.JSON
13429 * Modified version of Douglas Crockford"s json.js that doesn"t
13430 * mess with the Object prototype
13431 * http://www.json.org/js.html
13434 Roo.util.JSON = new (function(){
13435 var useHasOwn = {}.hasOwnProperty ? true : false;
13437 // crashes Safari in some instances
13438 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13440 var pad = function(n) {
13441 return n < 10 ? "0" + n : n;
13454 var encodeString = function(s){
13455 if (/["\\\x00-\x1f]/.test(s)) {
13456 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13461 c = b.charCodeAt();
13463 Math.floor(c / 16).toString(16) +
13464 (c % 16).toString(16);
13467 return '"' + s + '"';
13470 var encodeArray = function(o){
13471 var a = ["["], b, i, l = o.length, v;
13472 for (i = 0; i < l; i += 1) {
13474 switch (typeof v) {
13483 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13491 var encodeDate = function(o){
13492 return '"' + o.getFullYear() + "-" +
13493 pad(o.getMonth() + 1) + "-" +
13494 pad(o.getDate()) + "T" +
13495 pad(o.getHours()) + ":" +
13496 pad(o.getMinutes()) + ":" +
13497 pad(o.getSeconds()) + '"';
13501 * Encodes an Object, Array or other value
13502 * @param {Mixed} o The variable to encode
13503 * @return {String} The JSON string
13505 this.encode = function(o)
13507 // should this be extended to fully wrap stringify..
13509 if(typeof o == "undefined" || o === null){
13511 }else if(o instanceof Array){
13512 return encodeArray(o);
13513 }else if(o instanceof Date){
13514 return encodeDate(o);
13515 }else if(typeof o == "string"){
13516 return encodeString(o);
13517 }else if(typeof o == "number"){
13518 return isFinite(o) ? String(o) : "null";
13519 }else if(typeof o == "boolean"){
13522 var a = ["{"], b, i, v;
13524 if(!useHasOwn || o.hasOwnProperty(i)) {
13526 switch (typeof v) {
13535 a.push(this.encode(i), ":",
13536 v === null ? "null" : this.encode(v));
13547 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13548 * @param {String} json The JSON string
13549 * @return {Object} The resulting object
13551 this.decode = function(json){
13553 return /** eval:var:json */ eval("(" + json + ')');
13557 * Shorthand for {@link Roo.util.JSON#encode}
13558 * @member Roo encode
13560 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13562 * Shorthand for {@link Roo.util.JSON#decode}
13563 * @member Roo decode
13565 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13568 * Ext JS Library 1.1.1
13569 * Copyright(c) 2006-2007, Ext JS, LLC.
13571 * Originally Released Under LGPL - original licence link has changed is not relivant.
13574 * <script type="text/javascript">
13578 * @class Roo.util.Format
13579 * Reusable data formatting functions
13582 Roo.util.Format = function(){
13583 var trimRe = /^\s+|\s+$/g;
13586 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13587 * @param {String} value The string to truncate
13588 * @param {Number} length The maximum length to allow before truncating
13589 * @return {String} The converted text
13591 ellipsis : function(value, len){
13592 if(value && value.length > len){
13593 return value.substr(0, len-3)+"...";
13599 * Checks a reference and converts it to empty string if it is undefined
13600 * @param {Mixed} value Reference to check
13601 * @return {Mixed} Empty string if converted, otherwise the original value
13603 undef : function(value){
13604 return typeof value != "undefined" ? value : "";
13608 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13609 * @param {String} value The string to encode
13610 * @return {String} The encoded text
13612 htmlEncode : function(value){
13613 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13617 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13618 * @param {String} value The string to decode
13619 * @return {String} The decoded text
13621 htmlDecode : function(value){
13622 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13626 * Trims any whitespace from either side of a string
13627 * @param {String} value The text to trim
13628 * @return {String} The trimmed text
13630 trim : function(value){
13631 return String(value).replace(trimRe, "");
13635 * Returns a substring from within an original string
13636 * @param {String} value The original text
13637 * @param {Number} start The start index of the substring
13638 * @param {Number} length The length of the substring
13639 * @return {String} The substring
13641 substr : function(value, start, length){
13642 return String(value).substr(start, length);
13646 * Converts a string to all lower case letters
13647 * @param {String} value The text to convert
13648 * @return {String} The converted text
13650 lowercase : function(value){
13651 return String(value).toLowerCase();
13655 * Converts a string to all upper case letters
13656 * @param {String} value The text to convert
13657 * @return {String} The converted text
13659 uppercase : function(value){
13660 return String(value).toUpperCase();
13664 * Converts the first character only of a string to upper case
13665 * @param {String} value The text to convert
13666 * @return {String} The converted text
13668 capitalize : function(value){
13669 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13673 call : function(value, fn){
13674 if(arguments.length > 2){
13675 var args = Array.prototype.slice.call(arguments, 2);
13676 args.unshift(value);
13678 return /** eval:var:value */ eval(fn).apply(window, args);
13680 /** eval:var:value */
13681 return /** eval:var:value */ eval(fn).call(window, value);
13687 * safer version of Math.toFixed..??/
13688 * @param {Number/String} value The numeric value to format
13689 * @param {Number/String} value Decimal places
13690 * @return {String} The formatted currency string
13692 toFixed : function(v, n)
13694 // why not use to fixed - precision is buggered???
13696 return Math.round(v-0);
13698 var fact = Math.pow(10,n+1);
13699 v = (Math.round((v-0)*fact))/fact;
13700 var z = (''+fact).substring(2);
13701 if (v == Math.floor(v)) {
13702 return Math.floor(v) + '.' + z;
13705 // now just padd decimals..
13706 var ps = String(v).split('.');
13707 var fd = (ps[1] + z);
13708 var r = fd.substring(0,n);
13709 var rm = fd.substring(n);
13711 return ps[0] + '.' + r;
13713 r*=1; // turn it into a number;
13715 if (String(r).length != n) {
13718 r = String(r).substring(1); // chop the end off.
13721 return ps[0] + '.' + r;
13726 * Format a number as US currency
13727 * @param {Number/String} value The numeric value to format
13728 * @return {String} The formatted currency string
13730 usMoney : function(v){
13731 return '$' + Roo.util.Format.number(v);
13736 * eventually this should probably emulate php's number_format
13737 * @param {Number/String} value The numeric value to format
13738 * @param {Number} decimals number of decimal places
13739 * @return {String} The formatted currency string
13741 number : function(v,decimals)
13743 // multiply and round.
13744 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13745 var mul = Math.pow(10, decimals);
13746 var zero = String(mul).substring(1);
13747 v = (Math.round((v-0)*mul))/mul;
13749 // if it's '0' number.. then
13751 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13753 var ps = v.split('.');
13757 var r = /(\d+)(\d{3})/;
13759 while (r.test(whole)) {
13760 whole = whole.replace(r, '$1' + ',' + '$2');
13766 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13767 // does not have decimals
13768 (decimals ? ('.' + zero) : '');
13771 return whole + sub ;
13775 * Parse a value into a formatted date using the specified format pattern.
13776 * @param {Mixed} value The value to format
13777 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13778 * @return {String} The formatted date string
13780 date : function(v, format){
13784 if(!(v instanceof Date)){
13785 v = new Date(Date.parse(v));
13787 return v.dateFormat(format || Roo.util.Format.defaults.date);
13791 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13792 * @param {String} format Any valid date format string
13793 * @return {Function} The date formatting function
13795 dateRenderer : function(format){
13796 return function(v){
13797 return Roo.util.Format.date(v, format);
13802 stripTagsRE : /<\/?[^>]+>/gi,
13805 * Strips all HTML tags
13806 * @param {Mixed} value The text from which to strip tags
13807 * @return {String} The stripped text
13809 stripTags : function(v){
13810 return !v ? v : String(v).replace(this.stripTagsRE, "");
13814 Roo.util.Format.defaults = {
13818 * Ext JS Library 1.1.1
13819 * Copyright(c) 2006-2007, Ext JS, LLC.
13821 * Originally Released Under LGPL - original licence link has changed is not relivant.
13824 * <script type="text/javascript">
13831 * @class Roo.MasterTemplate
13832 * @extends Roo.Template
13833 * Provides a template that can have child templates. The syntax is:
13835 var t = new Roo.MasterTemplate(
13836 '<select name="{name}">',
13837 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13840 t.add('options', {value: 'foo', text: 'bar'});
13841 // or you can add multiple child elements in one shot
13842 t.addAll('options', [
13843 {value: 'foo', text: 'bar'},
13844 {value: 'foo2', text: 'bar2'},
13845 {value: 'foo3', text: 'bar3'}
13847 // then append, applying the master template values
13848 t.append('my-form', {name: 'my-select'});
13850 * A name attribute for the child template is not required if you have only one child
13851 * template or you want to refer to them by index.
13853 Roo.MasterTemplate = function(){
13854 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13855 this.originalHtml = this.html;
13857 var m, re = this.subTemplateRe;
13860 while(m = re.exec(this.html)){
13861 var name = m[1], content = m[2];
13866 tpl : new Roo.Template(content)
13869 st[name] = st[subIndex];
13871 st[subIndex].tpl.compile();
13872 st[subIndex].tpl.call = this.call.createDelegate(this);
13875 this.subCount = subIndex;
13878 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13880 * The regular expression used to match sub templates
13884 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13887 * Applies the passed values to a child template.
13888 * @param {String/Number} name (optional) The name or index of the child template
13889 * @param {Array/Object} values The values to be applied to the template
13890 * @return {MasterTemplate} this
13892 add : function(name, values){
13893 if(arguments.length == 1){
13894 values = arguments[0];
13897 var s = this.subs[name];
13898 s.buffer[s.buffer.length] = s.tpl.apply(values);
13903 * Applies all the passed values to a child template.
13904 * @param {String/Number} name (optional) The name or index of the child template
13905 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13906 * @param {Boolean} reset (optional) True to reset the template first
13907 * @return {MasterTemplate} this
13909 fill : function(name, values, reset){
13911 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13919 for(var i = 0, len = values.length; i < len; i++){
13920 this.add(name, values[i]);
13926 * Resets the template for reuse
13927 * @return {MasterTemplate} this
13929 reset : function(){
13931 for(var i = 0; i < this.subCount; i++){
13937 applyTemplate : function(values){
13939 var replaceIndex = -1;
13940 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13941 return s[++replaceIndex].buffer.join("");
13943 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13946 apply : function(){
13947 return this.applyTemplate.apply(this, arguments);
13950 compile : function(){return this;}
13954 * Alias for fill().
13957 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13959 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13960 * var tpl = Roo.MasterTemplate.from('element-id');
13961 * @param {String/HTMLElement} el
13962 * @param {Object} config
13965 Roo.MasterTemplate.from = function(el, config){
13966 el = Roo.getDom(el);
13967 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13970 * Ext JS Library 1.1.1
13971 * Copyright(c) 2006-2007, Ext JS, LLC.
13973 * Originally Released Under LGPL - original licence link has changed is not relivant.
13976 * <script type="text/javascript">
13981 * @class Roo.util.CSS
13982 * Utility class for manipulating CSS rules
13985 Roo.util.CSS = function(){
13987 var doc = document;
13989 var camelRe = /(-[a-z])/gi;
13990 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13994 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13995 * tag and appended to the HEAD of the document.
13996 * @param {String|Object} cssText The text containing the css rules
13997 * @param {String} id An id to add to the stylesheet for later removal
13998 * @return {StyleSheet}
14000 createStyleSheet : function(cssText, id){
14002 var head = doc.getElementsByTagName("head")[0];
14003 var nrules = doc.createElement("style");
14004 nrules.setAttribute("type", "text/css");
14006 nrules.setAttribute("id", id);
14008 if (typeof(cssText) != 'string') {
14009 // support object maps..
14010 // not sure if this a good idea..
14011 // perhaps it should be merged with the general css handling
14012 // and handle js style props.
14013 var cssTextNew = [];
14014 for(var n in cssText) {
14016 for(var k in cssText[n]) {
14017 citems.push( k + ' : ' +cssText[n][k] + ';' );
14019 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14022 cssText = cssTextNew.join("\n");
14028 head.appendChild(nrules);
14029 ss = nrules.styleSheet;
14030 ss.cssText = cssText;
14033 nrules.appendChild(doc.createTextNode(cssText));
14035 nrules.cssText = cssText;
14037 head.appendChild(nrules);
14038 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14040 this.cacheStyleSheet(ss);
14045 * Removes a style or link tag by id
14046 * @param {String} id The id of the tag
14048 removeStyleSheet : function(id){
14049 var existing = doc.getElementById(id);
14051 existing.parentNode.removeChild(existing);
14056 * Dynamically swaps an existing stylesheet reference for a new one
14057 * @param {String} id The id of an existing link tag to remove
14058 * @param {String} url The href of the new stylesheet to include
14060 swapStyleSheet : function(id, url){
14061 this.removeStyleSheet(id);
14062 var ss = doc.createElement("link");
14063 ss.setAttribute("rel", "stylesheet");
14064 ss.setAttribute("type", "text/css");
14065 ss.setAttribute("id", id);
14066 ss.setAttribute("href", url);
14067 doc.getElementsByTagName("head")[0].appendChild(ss);
14071 * Refresh the rule cache if you have dynamically added stylesheets
14072 * @return {Object} An object (hash) of rules indexed by selector
14074 refreshCache : function(){
14075 return this.getRules(true);
14079 cacheStyleSheet : function(stylesheet){
14083 try{// try catch for cross domain access issue
14084 var ssRules = stylesheet.cssRules || stylesheet.rules;
14085 for(var j = ssRules.length-1; j >= 0; --j){
14086 rules[ssRules[j].selectorText] = ssRules[j];
14092 * Gets all css rules for the document
14093 * @param {Boolean} refreshCache true to refresh the internal cache
14094 * @return {Object} An object (hash) of rules indexed by selector
14096 getRules : function(refreshCache){
14097 if(rules == null || refreshCache){
14099 var ds = doc.styleSheets;
14100 for(var i =0, len = ds.length; i < len; i++){
14102 this.cacheStyleSheet(ds[i]);
14110 * Gets an an individual CSS rule by selector(s)
14111 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14112 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14113 * @return {CSSRule} The CSS rule or null if one is not found
14115 getRule : function(selector, refreshCache){
14116 var rs = this.getRules(refreshCache);
14117 if(!(selector instanceof Array)){
14118 return rs[selector];
14120 for(var i = 0; i < selector.length; i++){
14121 if(rs[selector[i]]){
14122 return rs[selector[i]];
14130 * Updates a rule property
14131 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14132 * @param {String} property The css property
14133 * @param {String} value The new value for the property
14134 * @return {Boolean} true If a rule was found and updated
14136 updateRule : function(selector, property, value){
14137 if(!(selector instanceof Array)){
14138 var rule = this.getRule(selector);
14140 rule.style[property.replace(camelRe, camelFn)] = value;
14144 for(var i = 0; i < selector.length; i++){
14145 if(this.updateRule(selector[i], property, value)){
14155 * Ext JS Library 1.1.1
14156 * Copyright(c) 2006-2007, Ext JS, LLC.
14158 * Originally Released Under LGPL - original licence link has changed is not relivant.
14161 * <script type="text/javascript">
14167 * @class Roo.util.ClickRepeater
14168 * @extends Roo.util.Observable
14170 * A wrapper class which can be applied to any element. Fires a "click" event while the
14171 * mouse is pressed. The interval between firings may be specified in the config but
14172 * defaults to 10 milliseconds.
14174 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14176 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14177 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14178 * Similar to an autorepeat key delay.
14179 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14180 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14181 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14182 * "interval" and "delay" are ignored. "immediate" is honored.
14183 * @cfg {Boolean} preventDefault True to prevent the default click event
14184 * @cfg {Boolean} stopDefault True to stop the default click event
14187 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14188 * 2007-02-02 jvs Renamed to ClickRepeater
14189 * 2007-02-03 jvs Modifications for FF Mac and Safari
14192 * @param {String/HTMLElement/Element} el The element to listen on
14193 * @param {Object} config
14195 Roo.util.ClickRepeater = function(el, config)
14197 this.el = Roo.get(el);
14198 this.el.unselectable();
14200 Roo.apply(this, config);
14205 * Fires when the mouse button is depressed.
14206 * @param {Roo.util.ClickRepeater} this
14208 "mousedown" : true,
14211 * Fires on a specified interval during the time the element is pressed.
14212 * @param {Roo.util.ClickRepeater} this
14217 * Fires when the mouse key is released.
14218 * @param {Roo.util.ClickRepeater} this
14223 this.el.on("mousedown", this.handleMouseDown, this);
14224 if(this.preventDefault || this.stopDefault){
14225 this.el.on("click", function(e){
14226 if(this.preventDefault){
14227 e.preventDefault();
14229 if(this.stopDefault){
14235 // allow inline handler
14237 this.on("click", this.handler, this.scope || this);
14240 Roo.util.ClickRepeater.superclass.constructor.call(this);
14243 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14246 preventDefault : true,
14247 stopDefault : false,
14251 handleMouseDown : function(){
14252 clearTimeout(this.timer);
14254 if(this.pressClass){
14255 this.el.addClass(this.pressClass);
14257 this.mousedownTime = new Date();
14259 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14260 this.el.on("mouseout", this.handleMouseOut, this);
14262 this.fireEvent("mousedown", this);
14263 this.fireEvent("click", this);
14265 this.timer = this.click.defer(this.delay || this.interval, this);
14269 click : function(){
14270 this.fireEvent("click", this);
14271 this.timer = this.click.defer(this.getInterval(), this);
14275 getInterval: function(){
14276 if(!this.accelerate){
14277 return this.interval;
14279 var pressTime = this.mousedownTime.getElapsed();
14280 if(pressTime < 500){
14282 }else if(pressTime < 1700){
14284 }else if(pressTime < 2600){
14286 }else if(pressTime < 3500){
14288 }else if(pressTime < 4400){
14290 }else if(pressTime < 5300){
14292 }else if(pressTime < 6200){
14300 handleMouseOut : function(){
14301 clearTimeout(this.timer);
14302 if(this.pressClass){
14303 this.el.removeClass(this.pressClass);
14305 this.el.on("mouseover", this.handleMouseReturn, this);
14309 handleMouseReturn : function(){
14310 this.el.un("mouseover", this.handleMouseReturn);
14311 if(this.pressClass){
14312 this.el.addClass(this.pressClass);
14318 handleMouseUp : function(){
14319 clearTimeout(this.timer);
14320 this.el.un("mouseover", this.handleMouseReturn);
14321 this.el.un("mouseout", this.handleMouseOut);
14322 Roo.get(document).un("mouseup", this.handleMouseUp);
14323 this.el.removeClass(this.pressClass);
14324 this.fireEvent("mouseup", this);
14328 * Ext JS Library 1.1.1
14329 * Copyright(c) 2006-2007, Ext JS, LLC.
14331 * Originally Released Under LGPL - original licence link has changed is not relivant.
14334 * <script type="text/javascript">
14339 * @class Roo.KeyNav
14340 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14341 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14342 * way to implement custom navigation schemes for any UI component.</p>
14343 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14344 * pageUp, pageDown, del, home, end. Usage:</p>
14346 var nav = new Roo.KeyNav("my-element", {
14347 "left" : function(e){
14348 this.moveLeft(e.ctrlKey);
14350 "right" : function(e){
14351 this.moveRight(e.ctrlKey);
14353 "enter" : function(e){
14360 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14361 * @param {Object} config The config
14363 Roo.KeyNav = function(el, config){
14364 this.el = Roo.get(el);
14365 Roo.apply(this, config);
14366 if(!this.disabled){
14367 this.disabled = true;
14372 Roo.KeyNav.prototype = {
14374 * @cfg {Boolean} disabled
14375 * True to disable this KeyNav instance (defaults to false)
14379 * @cfg {String} defaultEventAction
14380 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14381 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14382 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14384 defaultEventAction: "stopEvent",
14386 * @cfg {Boolean} forceKeyDown
14387 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14388 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14389 * handle keydown instead of keypress.
14391 forceKeyDown : false,
14394 prepareEvent : function(e){
14395 var k = e.getKey();
14396 var h = this.keyToHandler[k];
14397 //if(h && this[h]){
14398 // e.stopPropagation();
14400 if(Roo.isSafari && h && k >= 37 && k <= 40){
14406 relay : function(e){
14407 var k = e.getKey();
14408 var h = this.keyToHandler[k];
14410 if(this.doRelay(e, this[h], h) !== true){
14411 e[this.defaultEventAction]();
14417 doRelay : function(e, h, hname){
14418 return h.call(this.scope || this, e);
14421 // possible handlers
14435 // quick lookup hash
14452 * Enable this KeyNav
14454 enable: function(){
14456 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14457 // the EventObject will normalize Safari automatically
14458 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14459 this.el.on("keydown", this.relay, this);
14461 this.el.on("keydown", this.prepareEvent, this);
14462 this.el.on("keypress", this.relay, this);
14464 this.disabled = false;
14469 * Disable this KeyNav
14471 disable: function(){
14472 if(!this.disabled){
14473 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14474 this.el.un("keydown", this.relay);
14476 this.el.un("keydown", this.prepareEvent);
14477 this.el.un("keypress", this.relay);
14479 this.disabled = true;
14484 * Ext JS Library 1.1.1
14485 * Copyright(c) 2006-2007, Ext JS, LLC.
14487 * Originally Released Under LGPL - original licence link has changed is not relivant.
14490 * <script type="text/javascript">
14495 * @class Roo.KeyMap
14496 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14497 * The constructor accepts the same config object as defined by {@link #addBinding}.
14498 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14499 * combination it will call the function with this signature (if the match is a multi-key
14500 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14501 * A KeyMap can also handle a string representation of keys.<br />
14504 // map one key by key code
14505 var map = new Roo.KeyMap("my-element", {
14506 key: 13, // or Roo.EventObject.ENTER
14511 // map multiple keys to one action by string
14512 var map = new Roo.KeyMap("my-element", {
14518 // map multiple keys to multiple actions by strings and array of codes
14519 var map = new Roo.KeyMap("my-element", [
14522 fn: function(){ alert("Return was pressed"); }
14525 fn: function(){ alert('a, b or c was pressed'); }
14530 fn: function(){ alert('Control + shift + tab was pressed.'); }
14534 * <b>Note: A KeyMap starts enabled</b>
14536 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14537 * @param {Object} config The config (see {@link #addBinding})
14538 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14540 Roo.KeyMap = function(el, config, eventName){
14541 this.el = Roo.get(el);
14542 this.eventName = eventName || "keydown";
14543 this.bindings = [];
14545 this.addBinding(config);
14550 Roo.KeyMap.prototype = {
14552 * True to stop the event from bubbling and prevent the default browser action if the
14553 * key was handled by the KeyMap (defaults to false)
14559 * Add a new binding to this KeyMap. The following config object properties are supported:
14561 Property Type Description
14562 ---------- --------------- ----------------------------------------------------------------------
14563 key String/Array A single keycode or an array of keycodes to handle
14564 shift Boolean True to handle key only when shift is pressed (defaults to false)
14565 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14566 alt Boolean True to handle key only when alt is pressed (defaults to false)
14567 fn Function The function to call when KeyMap finds the expected key combination
14568 scope Object The scope of the callback function
14574 var map = new Roo.KeyMap(document, {
14575 key: Roo.EventObject.ENTER,
14580 //Add a new binding to the existing KeyMap later
14588 * @param {Object/Array} config A single KeyMap config or an array of configs
14590 addBinding : function(config){
14591 if(config instanceof Array){
14592 for(var i = 0, len = config.length; i < len; i++){
14593 this.addBinding(config[i]);
14597 var keyCode = config.key,
14598 shift = config.shift,
14599 ctrl = config.ctrl,
14602 scope = config.scope;
14603 if(typeof keyCode == "string"){
14605 var keyString = keyCode.toUpperCase();
14606 for(var j = 0, len = keyString.length; j < len; j++){
14607 ks.push(keyString.charCodeAt(j));
14611 var keyArray = keyCode instanceof Array;
14612 var handler = function(e){
14613 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14614 var k = e.getKey();
14616 for(var i = 0, len = keyCode.length; i < len; i++){
14617 if(keyCode[i] == k){
14618 if(this.stopEvent){
14621 fn.call(scope || window, k, e);
14627 if(this.stopEvent){
14630 fn.call(scope || window, k, e);
14635 this.bindings.push(handler);
14639 * Shorthand for adding a single key listener
14640 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14641 * following options:
14642 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14643 * @param {Function} fn The function to call
14644 * @param {Object} scope (optional) The scope of the function
14646 on : function(key, fn, scope){
14647 var keyCode, shift, ctrl, alt;
14648 if(typeof key == "object" && !(key instanceof Array)){
14667 handleKeyDown : function(e){
14668 if(this.enabled){ //just in case
14669 var b = this.bindings;
14670 for(var i = 0, len = b.length; i < len; i++){
14671 b[i].call(this, e);
14677 * Returns true if this KeyMap is enabled
14678 * @return {Boolean}
14680 isEnabled : function(){
14681 return this.enabled;
14685 * Enables this KeyMap
14687 enable: function(){
14689 this.el.on(this.eventName, this.handleKeyDown, this);
14690 this.enabled = true;
14695 * Disable this KeyMap
14697 disable: function(){
14699 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14700 this.enabled = false;
14705 * Ext JS Library 1.1.1
14706 * Copyright(c) 2006-2007, Ext JS, LLC.
14708 * Originally Released Under LGPL - original licence link has changed is not relivant.
14711 * <script type="text/javascript">
14716 * @class Roo.util.TextMetrics
14717 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14718 * wide, in pixels, a given block of text will be.
14721 Roo.util.TextMetrics = function(){
14725 * Measures the size of the specified text
14726 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14727 * that can affect the size of the rendered text
14728 * @param {String} text The text to measure
14729 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14730 * in order to accurately measure the text height
14731 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14733 measure : function(el, text, fixedWidth){
14735 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14738 shared.setFixedWidth(fixedWidth || 'auto');
14739 return shared.getSize(text);
14743 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14744 * the overhead of multiple calls to initialize the style properties on each measurement.
14745 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14746 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14747 * in order to accurately measure the text height
14748 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14750 createInstance : function(el, fixedWidth){
14751 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14758 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14759 var ml = new Roo.Element(document.createElement('div'));
14760 document.body.appendChild(ml.dom);
14761 ml.position('absolute');
14762 ml.setLeftTop(-1000, -1000);
14766 ml.setWidth(fixedWidth);
14771 * Returns the size of the specified text based on the internal element's style and width properties
14772 * @memberOf Roo.util.TextMetrics.Instance#
14773 * @param {String} text The text to measure
14774 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14776 getSize : function(text){
14778 var s = ml.getSize();
14784 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14785 * that can affect the size of the rendered text
14786 * @memberOf Roo.util.TextMetrics.Instance#
14787 * @param {String/HTMLElement} el The element, dom node or id
14789 bind : function(el){
14791 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14796 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14797 * to set a fixed width in order to accurately measure the text height.
14798 * @memberOf Roo.util.TextMetrics.Instance#
14799 * @param {Number} width The width to set on the element
14801 setFixedWidth : function(width){
14802 ml.setWidth(width);
14806 * Returns the measured width of the specified text
14807 * @memberOf Roo.util.TextMetrics.Instance#
14808 * @param {String} text The text to measure
14809 * @return {Number} width The width in pixels
14811 getWidth : function(text){
14812 ml.dom.style.width = 'auto';
14813 return this.getSize(text).width;
14817 * Returns the measured height of the specified text. For multiline text, be sure to call
14818 * {@link #setFixedWidth} if necessary.
14819 * @memberOf Roo.util.TextMetrics.Instance#
14820 * @param {String} text The text to measure
14821 * @return {Number} height The height in pixels
14823 getHeight : function(text){
14824 return this.getSize(text).height;
14828 instance.bind(bindTo);
14833 // backwards compat
14834 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14836 * Ext JS Library 1.1.1
14837 * Copyright(c) 2006-2007, Ext JS, LLC.
14839 * Originally Released Under LGPL - original licence link has changed is not relivant.
14842 * <script type="text/javascript">
14846 * @class Roo.state.Provider
14847 * Abstract base class for state provider implementations. This class provides methods
14848 * for encoding and decoding <b>typed</b> variables including dates and defines the
14849 * Provider interface.
14851 Roo.state.Provider = function(){
14853 * @event statechange
14854 * Fires when a state change occurs.
14855 * @param {Provider} this This state provider
14856 * @param {String} key The state key which was changed
14857 * @param {String} value The encoded value for the state
14860 "statechange": true
14863 Roo.state.Provider.superclass.constructor.call(this);
14865 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14867 * Returns the current value for a key
14868 * @param {String} name The key name
14869 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14870 * @return {Mixed} The state data
14872 get : function(name, defaultValue){
14873 return typeof this.state[name] == "undefined" ?
14874 defaultValue : this.state[name];
14878 * Clears a value from the state
14879 * @param {String} name The key name
14881 clear : function(name){
14882 delete this.state[name];
14883 this.fireEvent("statechange", this, name, null);
14887 * Sets the value for a key
14888 * @param {String} name The key name
14889 * @param {Mixed} value The value to set
14891 set : function(name, value){
14892 this.state[name] = value;
14893 this.fireEvent("statechange", this, name, value);
14897 * Decodes a string previously encoded with {@link #encodeValue}.
14898 * @param {String} value The value to decode
14899 * @return {Mixed} The decoded value
14901 decodeValue : function(cookie){
14902 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14903 var matches = re.exec(unescape(cookie));
14904 if(!matches || !matches[1]) {
14905 return; // non state cookie
14907 var type = matches[1];
14908 var v = matches[2];
14911 return parseFloat(v);
14913 return new Date(Date.parse(v));
14918 var values = v.split("^");
14919 for(var i = 0, len = values.length; i < len; i++){
14920 all.push(this.decodeValue(values[i]));
14925 var values = v.split("^");
14926 for(var i = 0, len = values.length; i < len; i++){
14927 var kv = values[i].split("=");
14928 all[kv[0]] = this.decodeValue(kv[1]);
14937 * Encodes a value including type information. Decode with {@link #decodeValue}.
14938 * @param {Mixed} value The value to encode
14939 * @return {String} The encoded value
14941 encodeValue : function(v){
14943 if(typeof v == "number"){
14945 }else if(typeof v == "boolean"){
14946 enc = "b:" + (v ? "1" : "0");
14947 }else if(v instanceof Date){
14948 enc = "d:" + v.toGMTString();
14949 }else if(v instanceof Array){
14951 for(var i = 0, len = v.length; i < len; i++){
14952 flat += this.encodeValue(v[i]);
14958 }else if(typeof v == "object"){
14961 if(typeof v[key] != "function"){
14962 flat += key + "=" + this.encodeValue(v[key]) + "^";
14965 enc = "o:" + flat.substring(0, flat.length-1);
14969 return escape(enc);
14975 * Ext JS Library 1.1.1
14976 * Copyright(c) 2006-2007, Ext JS, LLC.
14978 * Originally Released Under LGPL - original licence link has changed is not relivant.
14981 * <script type="text/javascript">
14984 * @class Roo.state.Manager
14985 * This is the global state manager. By default all components that are "state aware" check this class
14986 * for state information if you don't pass them a custom state provider. In order for this class
14987 * to be useful, it must be initialized with a provider when your application initializes.
14989 // in your initialization function
14991 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14993 // supposed you have a {@link Roo.BorderLayout}
14994 var layout = new Roo.BorderLayout(...);
14995 layout.restoreState();
14996 // or a {Roo.BasicDialog}
14997 var dialog = new Roo.BasicDialog(...);
14998 dialog.restoreState();
15002 Roo.state.Manager = function(){
15003 var provider = new Roo.state.Provider();
15007 * Configures the default state provider for your application
15008 * @param {Provider} stateProvider The state provider to set
15010 setProvider : function(stateProvider){
15011 provider = stateProvider;
15015 * Returns the current value for a key
15016 * @param {String} name The key name
15017 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15018 * @return {Mixed} The state data
15020 get : function(key, defaultValue){
15021 return provider.get(key, defaultValue);
15025 * Sets the value for a key
15026 * @param {String} name The key name
15027 * @param {Mixed} value The state data
15029 set : function(key, value){
15030 provider.set(key, value);
15034 * Clears a value from the state
15035 * @param {String} name The key name
15037 clear : function(key){
15038 provider.clear(key);
15042 * Gets the currently configured state provider
15043 * @return {Provider} The state provider
15045 getProvider : function(){
15052 * Ext JS Library 1.1.1
15053 * Copyright(c) 2006-2007, Ext JS, LLC.
15055 * Originally Released Under LGPL - original licence link has changed is not relivant.
15058 * <script type="text/javascript">
15061 * @class Roo.state.CookieProvider
15062 * @extends Roo.state.Provider
15063 * The default Provider implementation which saves state via cookies.
15066 var cp = new Roo.state.CookieProvider({
15068 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15069 domain: "roojs.com"
15071 Roo.state.Manager.setProvider(cp);
15073 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15074 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15075 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15076 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15077 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15078 * domain the page is running on including the 'www' like 'www.roojs.com')
15079 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15081 * Create a new CookieProvider
15082 * @param {Object} config The configuration object
15084 Roo.state.CookieProvider = function(config){
15085 Roo.state.CookieProvider.superclass.constructor.call(this);
15087 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15088 this.domain = null;
15089 this.secure = false;
15090 Roo.apply(this, config);
15091 this.state = this.readCookies();
15094 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15096 set : function(name, value){
15097 if(typeof value == "undefined" || value === null){
15101 this.setCookie(name, value);
15102 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15106 clear : function(name){
15107 this.clearCookie(name);
15108 Roo.state.CookieProvider.superclass.clear.call(this, name);
15112 readCookies : function(){
15114 var c = document.cookie + ";";
15115 var re = /\s?(.*?)=(.*?);/g;
15117 while((matches = re.exec(c)) != null){
15118 var name = matches[1];
15119 var value = matches[2];
15120 if(name && name.substring(0,3) == "ys-"){
15121 cookies[name.substr(3)] = this.decodeValue(value);
15128 setCookie : function(name, value){
15129 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15130 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15131 ((this.path == null) ? "" : ("; path=" + this.path)) +
15132 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15133 ((this.secure == true) ? "; secure" : "");
15137 clearCookie : function(name){
15138 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15139 ((this.path == null) ? "" : ("; path=" + this.path)) +
15140 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15141 ((this.secure == true) ? "; secure" : "");
15145 * Ext JS Library 1.1.1
15146 * Copyright(c) 2006-2007, Ext JS, LLC.
15148 * Originally Released Under LGPL - original licence link has changed is not relivant.
15151 * <script type="text/javascript">
15156 * @class Roo.ComponentMgr
15157 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15160 Roo.ComponentMgr = function(){
15161 var all = new Roo.util.MixedCollection();
15165 * Registers a component.
15166 * @param {Roo.Component} c The component
15168 register : function(c){
15173 * Unregisters a component.
15174 * @param {Roo.Component} c The component
15176 unregister : function(c){
15181 * Returns a component by id
15182 * @param {String} id The component id
15184 get : function(id){
15185 return all.get(id);
15189 * Registers a function that will be called when a specified component is added to ComponentMgr
15190 * @param {String} id The component id
15191 * @param {Funtction} fn The callback function
15192 * @param {Object} scope The scope of the callback
15194 onAvailable : function(id, fn, scope){
15195 all.on("add", function(index, o){
15197 fn.call(scope || o, o);
15198 all.un("add", fn, scope);
15205 * Ext JS Library 1.1.1
15206 * Copyright(c) 2006-2007, Ext JS, LLC.
15208 * Originally Released Under LGPL - original licence link has changed is not relivant.
15211 * <script type="text/javascript">
15215 * @class Roo.Component
15216 * @extends Roo.util.Observable
15217 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15218 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15219 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15220 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15221 * All visual components (widgets) that require rendering into a layout should subclass Component.
15223 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15224 * 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
15225 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15227 Roo.Component = function(config){
15228 config = config || {};
15229 if(config.tagName || config.dom || typeof config == "string"){ // element object
15230 config = {el: config, id: config.id || config};
15232 this.initialConfig = config;
15234 Roo.apply(this, config);
15238 * Fires after the component is disabled.
15239 * @param {Roo.Component} this
15244 * Fires after the component is enabled.
15245 * @param {Roo.Component} this
15249 * @event beforeshow
15250 * Fires before the component is shown. Return false to stop the show.
15251 * @param {Roo.Component} this
15256 * Fires after the component is shown.
15257 * @param {Roo.Component} this
15261 * @event beforehide
15262 * Fires before the component is hidden. Return false to stop the hide.
15263 * @param {Roo.Component} this
15268 * Fires after the component is hidden.
15269 * @param {Roo.Component} this
15273 * @event beforerender
15274 * Fires before the component is rendered. Return false to stop the render.
15275 * @param {Roo.Component} this
15277 beforerender : true,
15280 * Fires after the component is rendered.
15281 * @param {Roo.Component} this
15285 * @event beforedestroy
15286 * Fires before the component is destroyed. Return false to stop the destroy.
15287 * @param {Roo.Component} this
15289 beforedestroy : true,
15292 * Fires after the component is destroyed.
15293 * @param {Roo.Component} this
15298 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15300 Roo.ComponentMgr.register(this);
15301 Roo.Component.superclass.constructor.call(this);
15302 this.initComponent();
15303 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15304 this.render(this.renderTo);
15305 delete this.renderTo;
15310 Roo.Component.AUTO_ID = 1000;
15312 Roo.extend(Roo.Component, Roo.util.Observable, {
15314 * @scope Roo.Component.prototype
15316 * true if this component is hidden. Read-only.
15321 * true if this component is disabled. Read-only.
15326 * true if this component has been rendered. Read-only.
15330 /** @cfg {String} disableClass
15331 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15333 disabledClass : "x-item-disabled",
15334 /** @cfg {Boolean} allowDomMove
15335 * Whether the component can move the Dom node when rendering (defaults to true).
15337 allowDomMove : true,
15338 /** @cfg {String} hideMode (display|visibility)
15339 * How this component should hidden. Supported values are
15340 * "visibility" (css visibility), "offsets" (negative offset position) and
15341 * "display" (css display) - defaults to "display".
15343 hideMode: 'display',
15346 ctype : "Roo.Component",
15349 * @cfg {String} actionMode
15350 * which property holds the element that used for hide() / show() / disable() / enable()
15356 getActionEl : function(){
15357 return this[this.actionMode];
15360 initComponent : Roo.emptyFn,
15362 * If this is a lazy rendering component, render it to its container element.
15363 * @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.
15365 render : function(container, position){
15366 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15367 if(!container && this.el){
15368 this.el = Roo.get(this.el);
15369 container = this.el.dom.parentNode;
15370 this.allowDomMove = false;
15372 this.container = Roo.get(container);
15373 this.rendered = true;
15374 if(position !== undefined){
15375 if(typeof position == 'number'){
15376 position = this.container.dom.childNodes[position];
15378 position = Roo.getDom(position);
15381 this.onRender(this.container, position || null);
15383 this.el.addClass(this.cls);
15387 this.el.applyStyles(this.style);
15390 this.fireEvent("render", this);
15391 this.afterRender(this.container);
15403 // default function is not really useful
15404 onRender : function(ct, position){
15406 this.el = Roo.get(this.el);
15407 if(this.allowDomMove !== false){
15408 ct.dom.insertBefore(this.el.dom, position);
15414 getAutoCreate : function(){
15415 var cfg = typeof this.autoCreate == "object" ?
15416 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15417 if(this.id && !cfg.id){
15424 afterRender : Roo.emptyFn,
15427 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15428 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15430 destroy : function(){
15431 if(this.fireEvent("beforedestroy", this) !== false){
15432 this.purgeListeners();
15433 this.beforeDestroy();
15435 this.el.removeAllListeners();
15437 if(this.actionMode == "container"){
15438 this.container.remove();
15442 Roo.ComponentMgr.unregister(this);
15443 this.fireEvent("destroy", this);
15448 beforeDestroy : function(){
15453 onDestroy : function(){
15458 * Returns the underlying {@link Roo.Element}.
15459 * @return {Roo.Element} The element
15461 getEl : function(){
15466 * Returns the id of this component.
15469 getId : function(){
15474 * Try to focus this component.
15475 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15476 * @return {Roo.Component} this
15478 focus : function(selectText){
15481 if(selectText === true){
15482 this.el.dom.select();
15497 * Disable this component.
15498 * @return {Roo.Component} this
15500 disable : function(){
15504 this.disabled = true;
15505 this.fireEvent("disable", this);
15510 onDisable : function(){
15511 this.getActionEl().addClass(this.disabledClass);
15512 this.el.dom.disabled = true;
15516 * Enable this component.
15517 * @return {Roo.Component} this
15519 enable : function(){
15523 this.disabled = false;
15524 this.fireEvent("enable", this);
15529 onEnable : function(){
15530 this.getActionEl().removeClass(this.disabledClass);
15531 this.el.dom.disabled = false;
15535 * Convenience function for setting disabled/enabled by boolean.
15536 * @param {Boolean} disabled
15538 setDisabled : function(disabled){
15539 this[disabled ? "disable" : "enable"]();
15543 * Show this component.
15544 * @return {Roo.Component} this
15547 if(this.fireEvent("beforeshow", this) !== false){
15548 this.hidden = false;
15552 this.fireEvent("show", this);
15558 onShow : function(){
15559 var ae = this.getActionEl();
15560 if(this.hideMode == 'visibility'){
15561 ae.dom.style.visibility = "visible";
15562 }else if(this.hideMode == 'offsets'){
15563 ae.removeClass('x-hidden');
15565 ae.dom.style.display = "";
15570 * Hide this component.
15571 * @return {Roo.Component} this
15574 if(this.fireEvent("beforehide", this) !== false){
15575 this.hidden = true;
15579 this.fireEvent("hide", this);
15585 onHide : function(){
15586 var ae = this.getActionEl();
15587 if(this.hideMode == 'visibility'){
15588 ae.dom.style.visibility = "hidden";
15589 }else if(this.hideMode == 'offsets'){
15590 ae.addClass('x-hidden');
15592 ae.dom.style.display = "none";
15597 * Convenience function to hide or show this component by boolean.
15598 * @param {Boolean} visible True to show, false to hide
15599 * @return {Roo.Component} this
15601 setVisible: function(visible){
15611 * Returns true if this component is visible.
15613 isVisible : function(){
15614 return this.getActionEl().isVisible();
15617 cloneConfig : function(overrides){
15618 overrides = overrides || {};
15619 var id = overrides.id || Roo.id();
15620 var cfg = Roo.applyIf(overrides, this.initialConfig);
15621 cfg.id = id; // prevent dup id
15622 return new this.constructor(cfg);
15626 * Ext JS Library 1.1.1
15627 * Copyright(c) 2006-2007, Ext JS, LLC.
15629 * Originally Released Under LGPL - original licence link has changed is not relivant.
15632 * <script type="text/javascript">
15636 * @class Roo.BoxComponent
15637 * @extends Roo.Component
15638 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15639 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15640 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15641 * layout containers.
15643 * @param {Roo.Element/String/Object} config The configuration options.
15645 Roo.BoxComponent = function(config){
15646 Roo.Component.call(this, config);
15650 * Fires after the component is resized.
15651 * @param {Roo.Component} this
15652 * @param {Number} adjWidth The box-adjusted width that was set
15653 * @param {Number} adjHeight The box-adjusted height that was set
15654 * @param {Number} rawWidth The width that was originally specified
15655 * @param {Number} rawHeight The height that was originally specified
15660 * Fires after the component is moved.
15661 * @param {Roo.Component} this
15662 * @param {Number} x The new x position
15663 * @param {Number} y The new y position
15669 Roo.extend(Roo.BoxComponent, Roo.Component, {
15670 // private, set in afterRender to signify that the component has been rendered
15672 // private, used to defer height settings to subclasses
15673 deferHeight: false,
15674 /** @cfg {Number} width
15675 * width (optional) size of component
15677 /** @cfg {Number} height
15678 * height (optional) size of component
15682 * Sets the width and height of the component. This method fires the resize event. This method can accept
15683 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15684 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15685 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15686 * @return {Roo.BoxComponent} this
15688 setSize : function(w, h){
15689 // support for standard size objects
15690 if(typeof w == 'object'){
15695 if(!this.boxReady){
15701 // prevent recalcs when not needed
15702 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15705 this.lastSize = {width: w, height: h};
15707 var adj = this.adjustSize(w, h);
15708 var aw = adj.width, ah = adj.height;
15709 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15710 var rz = this.getResizeEl();
15711 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15712 rz.setSize(aw, ah);
15713 }else if(!this.deferHeight && ah !== undefined){
15715 }else if(aw !== undefined){
15718 this.onResize(aw, ah, w, h);
15719 this.fireEvent('resize', this, aw, ah, w, h);
15725 * Gets the current size of the component's underlying element.
15726 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15728 getSize : function(){
15729 return this.el.getSize();
15733 * Gets the current XY position of the component's underlying element.
15734 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15735 * @return {Array} The XY position of the element (e.g., [100, 200])
15737 getPosition : function(local){
15738 if(local === true){
15739 return [this.el.getLeft(true), this.el.getTop(true)];
15741 return this.xy || this.el.getXY();
15745 * Gets the current box measurements of the component's underlying element.
15746 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15747 * @returns {Object} box An object in the format {x, y, width, height}
15749 getBox : function(local){
15750 var s = this.el.getSize();
15752 s.x = this.el.getLeft(true);
15753 s.y = this.el.getTop(true);
15755 var xy = this.xy || this.el.getXY();
15763 * Sets the current box measurements of the component's underlying element.
15764 * @param {Object} box An object in the format {x, y, width, height}
15765 * @returns {Roo.BoxComponent} this
15767 updateBox : function(box){
15768 this.setSize(box.width, box.height);
15769 this.setPagePosition(box.x, box.y);
15774 getResizeEl : function(){
15775 return this.resizeEl || this.el;
15779 getPositionEl : function(){
15780 return this.positionEl || this.el;
15784 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15785 * This method fires the move event.
15786 * @param {Number} left The new left
15787 * @param {Number} top The new top
15788 * @returns {Roo.BoxComponent} this
15790 setPosition : function(x, y){
15793 if(!this.boxReady){
15796 var adj = this.adjustPosition(x, y);
15797 var ax = adj.x, ay = adj.y;
15799 var el = this.getPositionEl();
15800 if(ax !== undefined || ay !== undefined){
15801 if(ax !== undefined && ay !== undefined){
15802 el.setLeftTop(ax, ay);
15803 }else if(ax !== undefined){
15805 }else if(ay !== undefined){
15808 this.onPosition(ax, ay);
15809 this.fireEvent('move', this, ax, ay);
15815 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15816 * This method fires the move event.
15817 * @param {Number} x The new x position
15818 * @param {Number} y The new y position
15819 * @returns {Roo.BoxComponent} this
15821 setPagePosition : function(x, y){
15824 if(!this.boxReady){
15827 if(x === undefined || y === undefined){ // cannot translate undefined points
15830 var p = this.el.translatePoints(x, y);
15831 this.setPosition(p.left, p.top);
15836 onRender : function(ct, position){
15837 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15839 this.resizeEl = Roo.get(this.resizeEl);
15841 if(this.positionEl){
15842 this.positionEl = Roo.get(this.positionEl);
15847 afterRender : function(){
15848 Roo.BoxComponent.superclass.afterRender.call(this);
15849 this.boxReady = true;
15850 this.setSize(this.width, this.height);
15851 if(this.x || this.y){
15852 this.setPosition(this.x, this.y);
15854 if(this.pageX || this.pageY){
15855 this.setPagePosition(this.pageX, this.pageY);
15860 * Force the component's size to recalculate based on the underlying element's current height and width.
15861 * @returns {Roo.BoxComponent} this
15863 syncSize : function(){
15864 delete this.lastSize;
15865 this.setSize(this.el.getWidth(), this.el.getHeight());
15870 * Called after the component is resized, this method is empty by default but can be implemented by any
15871 * subclass that needs to perform custom logic after a resize occurs.
15872 * @param {Number} adjWidth The box-adjusted width that was set
15873 * @param {Number} adjHeight The box-adjusted height that was set
15874 * @param {Number} rawWidth The width that was originally specified
15875 * @param {Number} rawHeight The height that was originally specified
15877 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15882 * Called after the component is moved, this method is empty by default but can be implemented by any
15883 * subclass that needs to perform custom logic after a move occurs.
15884 * @param {Number} x The new x position
15885 * @param {Number} y The new y position
15887 onPosition : function(x, y){
15892 adjustSize : function(w, h){
15893 if(this.autoWidth){
15896 if(this.autoHeight){
15899 return {width : w, height: h};
15903 adjustPosition : function(x, y){
15904 return {x : x, y: y};
15907 * Original code for Roojs - LGPL
15908 * <script type="text/javascript">
15912 * @class Roo.XComponent
15913 * A delayed Element creator...
15914 * Or a way to group chunks of interface together.
15915 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15916 * used in conjunction with XComponent.build() it will create an instance of each element,
15917 * then call addxtype() to build the User interface.
15919 * Mypart.xyx = new Roo.XComponent({
15921 parent : 'Mypart.xyz', // empty == document.element.!!
15925 disabled : function() {}
15927 tree : function() { // return an tree of xtype declared components
15931 xtype : 'NestedLayoutPanel',
15938 * It can be used to build a big heiracy, with parent etc.
15939 * or you can just use this to render a single compoent to a dom element
15940 * MYPART.render(Roo.Element | String(id) | dom_element )
15947 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15948 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15950 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15952 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15953 * - if mulitple topModules exist, the last one is defined as the top module.
15957 * When the top level or multiple modules are to embedded into a existing HTML page,
15958 * the parent element can container '#id' of the element where the module will be drawn.
15962 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15963 * it relies more on a include mechanism, where sub modules are included into an outer page.
15964 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15966 * Bootstrap Roo Included elements
15968 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15969 * hence confusing the component builder as it thinks there are multiple top level elements.
15973 * @extends Roo.util.Observable
15975 * @param cfg {Object} configuration of component
15978 Roo.XComponent = function(cfg) {
15979 Roo.apply(this, cfg);
15983 * Fires when this the componnt is built
15984 * @param {Roo.XComponent} c the component
15989 this.region = this.region || 'center'; // default..
15990 Roo.XComponent.register(this);
15991 this.modules = false;
15992 this.el = false; // where the layout goes..
15996 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15999 * The created element (with Roo.factory())
16000 * @type {Roo.Layout}
16006 * for BC - use el in new code
16007 * @type {Roo.Layout}
16013 * for BC - use el in new code
16014 * @type {Roo.Layout}
16019 * @cfg {Function|boolean} disabled
16020 * If this module is disabled by some rule, return true from the funtion
16025 * @cfg {String} parent
16026 * Name of parent element which it get xtype added to..
16031 * @cfg {String} order
16032 * Used to set the order in which elements are created (usefull for multiple tabs)
16037 * @cfg {String} name
16038 * String to display while loading.
16042 * @cfg {String} region
16043 * Region to render component to (defaults to center)
16048 * @cfg {Array} items
16049 * A single item array - the first element is the root of the tree..
16050 * It's done this way to stay compatible with the Xtype system...
16056 * The method that retuns the tree of parts that make up this compoennt
16063 * render element to dom or tree
16064 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16067 render : function(el)
16071 var hp = this.parent ? 1 : 0;
16072 Roo.debug && Roo.log(this);
16074 var tree = this._tree ? this._tree() : this.tree();
16077 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16078 // if parent is a '#.....' string, then let's use that..
16079 var ename = this.parent.substr(1);
16080 this.parent = false;
16081 Roo.debug && Roo.log(ename);
16083 case 'bootstrap-body':
16084 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16085 // this is the BorderLayout standard?
16086 this.parent = { el : true };
16089 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16090 // need to insert stuff...
16092 el : new Roo.bootstrap.layout.Border({
16093 el : document.body,
16099 tabPosition: 'top',
16100 //resizeTabs: true,
16101 alwaysShowTabs: true,
16111 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16112 this.parent = { el : new Roo.bootstrap.Body() };
16113 Roo.debug && Roo.log("setting el to doc body");
16116 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16120 this.parent = { el : true};
16123 el = Roo.get(ename);
16124 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16125 this.parent = { el : true};
16132 if (!el && !this.parent) {
16133 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16138 Roo.debug && Roo.log("EL:");
16139 Roo.debug && Roo.log(el);
16140 Roo.debug && Roo.log("this.parent.el:");
16141 Roo.debug && Roo.log(this.parent.el);
16144 // altertive root elements ??? - we need a better way to indicate these.
16145 var is_alt = Roo.XComponent.is_alt ||
16146 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16147 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16148 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16152 if (!this.parent && is_alt) {
16153 //el = Roo.get(document.body);
16154 this.parent = { el : true };
16159 if (!this.parent) {
16161 Roo.debug && Roo.log("no parent - creating one");
16163 el = el ? Roo.get(el) : false;
16165 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16168 el : new Roo.bootstrap.layout.Border({
16169 el: el || document.body,
16175 tabPosition: 'top',
16176 //resizeTabs: true,
16177 alwaysShowTabs: false,
16180 overflow: 'visible'
16186 // it's a top level one..
16188 el : new Roo.BorderLayout(el || document.body, {
16193 tabPosition: 'top',
16194 //resizeTabs: true,
16195 alwaysShowTabs: el && hp? false : true,
16196 hideTabs: el || !hp ? true : false,
16204 if (!this.parent.el) {
16205 // probably an old style ctor, which has been disabled.
16209 // The 'tree' method is '_tree now'
16211 tree.region = tree.region || this.region;
16212 var is_body = false;
16213 if (this.parent.el === true) {
16214 // bootstrap... - body..
16218 this.parent.el = Roo.factory(tree);
16222 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16223 this.fireEvent('built', this);
16225 this.panel = this.el;
16226 this.layout = this.panel.layout;
16227 this.parentLayout = this.parent.layout || false;
16233 Roo.apply(Roo.XComponent, {
16235 * @property hideProgress
16236 * true to disable the building progress bar.. usefull on single page renders.
16239 hideProgress : false,
16241 * @property buildCompleted
16242 * True when the builder has completed building the interface.
16245 buildCompleted : false,
16248 * @property topModule
16249 * the upper most module - uses document.element as it's constructor.
16256 * @property modules
16257 * array of modules to be created by registration system.
16258 * @type {Array} of Roo.XComponent
16263 * @property elmodules
16264 * array of modules to be created by which use #ID
16265 * @type {Array} of Roo.XComponent
16272 * Is an alternative Root - normally used by bootstrap or other systems,
16273 * where the top element in the tree can wrap 'body'
16274 * @type {boolean} (default false)
16279 * @property build_from_html
16280 * Build elements from html - used by bootstrap HTML stuff
16281 * - this is cleared after build is completed
16282 * @type {boolean} (default false)
16285 build_from_html : false,
16287 * Register components to be built later.
16289 * This solves the following issues
16290 * - Building is not done on page load, but after an authentication process has occured.
16291 * - Interface elements are registered on page load
16292 * - Parent Interface elements may not be loaded before child, so this handles that..
16299 module : 'Pman.Tab.projectMgr',
16301 parent : 'Pman.layout',
16302 disabled : false, // or use a function..
16305 * * @param {Object} details about module
16307 register : function(obj) {
16309 Roo.XComponent.event.fireEvent('register', obj);
16310 switch(typeof(obj.disabled) ) {
16316 if ( obj.disabled() ) {
16322 if (obj.disabled) {
16328 this.modules.push(obj);
16332 * convert a string to an object..
16333 * eg. 'AAA.BBB' -> finds AAA.BBB
16337 toObject : function(str)
16339 if (!str || typeof(str) == 'object') {
16342 if (str.substring(0,1) == '#') {
16346 var ar = str.split('.');
16351 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16353 throw "Module not found : " + str;
16357 throw "Module not found : " + str;
16359 Roo.each(ar, function(e) {
16360 if (typeof(o[e]) == 'undefined') {
16361 throw "Module not found : " + str;
16372 * move modules into their correct place in the tree..
16375 preBuild : function ()
16378 Roo.each(this.modules , function (obj)
16380 Roo.XComponent.event.fireEvent('beforebuild', obj);
16382 var opar = obj.parent;
16384 obj.parent = this.toObject(opar);
16386 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16391 Roo.debug && Roo.log("GOT top level module");
16392 Roo.debug && Roo.log(obj);
16393 obj.modules = new Roo.util.MixedCollection(false,
16394 function(o) { return o.order + '' }
16396 this.topModule = obj;
16399 // parent is a string (usually a dom element name..)
16400 if (typeof(obj.parent) == 'string') {
16401 this.elmodules.push(obj);
16404 if (obj.parent.constructor != Roo.XComponent) {
16405 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16407 if (!obj.parent.modules) {
16408 obj.parent.modules = new Roo.util.MixedCollection(false,
16409 function(o) { return o.order + '' }
16412 if (obj.parent.disabled) {
16413 obj.disabled = true;
16415 obj.parent.modules.add(obj);
16420 * make a list of modules to build.
16421 * @return {Array} list of modules.
16424 buildOrder : function()
16427 var cmp = function(a,b) {
16428 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16430 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16431 throw "No top level modules to build";
16434 // make a flat list in order of modules to build.
16435 var mods = this.topModule ? [ this.topModule ] : [];
16438 // elmodules (is a list of DOM based modules )
16439 Roo.each(this.elmodules, function(e) {
16441 if (!this.topModule &&
16442 typeof(e.parent) == 'string' &&
16443 e.parent.substring(0,1) == '#' &&
16444 Roo.get(e.parent.substr(1))
16447 _this.topModule = e;
16453 // add modules to their parents..
16454 var addMod = function(m) {
16455 Roo.debug && Roo.log("build Order: add: " + m.name);
16458 if (m.modules && !m.disabled) {
16459 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16460 m.modules.keySort('ASC', cmp );
16461 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16463 m.modules.each(addMod);
16465 Roo.debug && Roo.log("build Order: no child modules");
16467 // not sure if this is used any more..
16469 m.finalize.name = m.name + " (clean up) ";
16470 mods.push(m.finalize);
16474 if (this.topModule && this.topModule.modules) {
16475 this.topModule.modules.keySort('ASC', cmp );
16476 this.topModule.modules.each(addMod);
16482 * Build the registered modules.
16483 * @param {Object} parent element.
16484 * @param {Function} optional method to call after module has been added.
16488 build : function(opts)
16491 if (typeof(opts) != 'undefined') {
16492 Roo.apply(this,opts);
16496 var mods = this.buildOrder();
16498 //this.allmods = mods;
16499 //Roo.debug && Roo.log(mods);
16501 if (!mods.length) { // should not happen
16502 throw "NO modules!!!";
16506 var msg = "Building Interface...";
16507 // flash it up as modal - so we store the mask!?
16508 if (!this.hideProgress && Roo.MessageBox) {
16509 Roo.MessageBox.show({ title: 'loading' });
16510 Roo.MessageBox.show({
16511 title: "Please wait...",
16520 var total = mods.length;
16523 var progressRun = function() {
16524 if (!mods.length) {
16525 Roo.debug && Roo.log('hide?');
16526 if (!this.hideProgress && Roo.MessageBox) {
16527 Roo.MessageBox.hide();
16529 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16531 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16537 var m = mods.shift();
16540 Roo.debug && Roo.log(m);
16541 // not sure if this is supported any more.. - modules that are are just function
16542 if (typeof(m) == 'function') {
16544 return progressRun.defer(10, _this);
16548 msg = "Building Interface " + (total - mods.length) +
16550 (m.name ? (' - ' + m.name) : '');
16551 Roo.debug && Roo.log(msg);
16552 if (!_this.hideProgress && Roo.MessageBox) {
16553 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16557 // is the module disabled?
16558 var disabled = (typeof(m.disabled) == 'function') ?
16559 m.disabled.call(m.module.disabled) : m.disabled;
16563 return progressRun(); // we do not update the display!
16571 // it's 10 on top level, and 1 on others??? why...
16572 return progressRun.defer(10, _this);
16575 progressRun.defer(1, _this);
16589 * wrapper for event.on - aliased later..
16590 * Typically use to register a event handler for register:
16592 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16601 Roo.XComponent.event = new Roo.util.Observable({
16605 * Fires when an Component is registered,
16606 * set the disable property on the Component to stop registration.
16607 * @param {Roo.XComponent} c the component being registerd.
16612 * @event beforebuild
16613 * Fires before each Component is built
16614 * can be used to apply permissions.
16615 * @param {Roo.XComponent} c the component being registerd.
16618 'beforebuild' : true,
16620 * @event buildcomplete
16621 * Fires on the top level element when all elements have been built
16622 * @param {Roo.XComponent} the top level component.
16624 'buildcomplete' : true
16629 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16632 * marked - a markdown parser
16633 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16634 * https://github.com/chjj/marked
16640 * Roo.Markdown - is a very crude wrapper around marked..
16644 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16646 * Note: move the sample code to the bottom of this
16647 * file before uncommenting it.
16652 Roo.Markdown.toHtml = function(text) {
16654 var c = new Roo.Markdown.marked.setOptions({
16655 renderer: new Roo.Markdown.marked.Renderer(),
16666 text = text.replace(/\\\n/g,' ');
16667 return Roo.Markdown.marked(text);
16672 // Wraps all "globals" so that the only thing
16673 // exposed is makeHtml().
16678 * Block-Level Grammar
16683 code: /^( {4}[^\n]+\n*)+/,
16685 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16686 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16688 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16689 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16690 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16691 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16692 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16694 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16698 block.bullet = /(?:[*+-]|\d+\.)/;
16699 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16700 block.item = replace(block.item, 'gm')
16701 (/bull/g, block.bullet)
16704 block.list = replace(block.list)
16705 (/bull/g, block.bullet)
16706 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16707 ('def', '\\n+(?=' + block.def.source + ')')
16710 block.blockquote = replace(block.blockquote)
16714 block._tag = '(?!(?:'
16715 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16716 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16717 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16719 block.html = replace(block.html)
16720 ('comment', /<!--[\s\S]*?-->/)
16721 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16722 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16723 (/tag/g, block._tag)
16726 block.paragraph = replace(block.paragraph)
16728 ('heading', block.heading)
16729 ('lheading', block.lheading)
16730 ('blockquote', block.blockquote)
16731 ('tag', '<' + block._tag)
16736 * Normal Block Grammar
16739 block.normal = merge({}, block);
16742 * GFM Block Grammar
16745 block.gfm = merge({}, block.normal, {
16746 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16748 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16751 block.gfm.paragraph = replace(block.paragraph)
16753 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16754 + block.list.source.replace('\\1', '\\3') + '|')
16758 * GFM + Tables Block Grammar
16761 block.tables = merge({}, block.gfm, {
16762 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16763 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16770 function Lexer(options) {
16772 this.tokens.links = {};
16773 this.options = options || marked.defaults;
16774 this.rules = block.normal;
16776 if (this.options.gfm) {
16777 if (this.options.tables) {
16778 this.rules = block.tables;
16780 this.rules = block.gfm;
16786 * Expose Block Rules
16789 Lexer.rules = block;
16792 * Static Lex Method
16795 Lexer.lex = function(src, options) {
16796 var lexer = new Lexer(options);
16797 return lexer.lex(src);
16804 Lexer.prototype.lex = function(src) {
16806 .replace(/\r\n|\r/g, '\n')
16807 .replace(/\t/g, ' ')
16808 .replace(/\u00a0/g, ' ')
16809 .replace(/\u2424/g, '\n');
16811 return this.token(src, true);
16818 Lexer.prototype.token = function(src, top, bq) {
16819 var src = src.replace(/^ +$/gm, '')
16832 if (cap = this.rules.newline.exec(src)) {
16833 src = src.substring(cap[0].length);
16834 if (cap[0].length > 1) {
16842 if (cap = this.rules.code.exec(src)) {
16843 src = src.substring(cap[0].length);
16844 cap = cap[0].replace(/^ {4}/gm, '');
16847 text: !this.options.pedantic
16848 ? cap.replace(/\n+$/, '')
16855 if (cap = this.rules.fences.exec(src)) {
16856 src = src.substring(cap[0].length);
16866 if (cap = this.rules.heading.exec(src)) {
16867 src = src.substring(cap[0].length);
16870 depth: cap[1].length,
16876 // table no leading pipe (gfm)
16877 if (top && (cap = this.rules.nptable.exec(src))) {
16878 src = src.substring(cap[0].length);
16882 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16883 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16884 cells: cap[3].replace(/\n$/, '').split('\n')
16887 for (i = 0; i < item.align.length; i++) {
16888 if (/^ *-+: *$/.test(item.align[i])) {
16889 item.align[i] = 'right';
16890 } else if (/^ *:-+: *$/.test(item.align[i])) {
16891 item.align[i] = 'center';
16892 } else if (/^ *:-+ *$/.test(item.align[i])) {
16893 item.align[i] = 'left';
16895 item.align[i] = null;
16899 for (i = 0; i < item.cells.length; i++) {
16900 item.cells[i] = item.cells[i].split(/ *\| */);
16903 this.tokens.push(item);
16909 if (cap = this.rules.lheading.exec(src)) {
16910 src = src.substring(cap[0].length);
16913 depth: cap[2] === '=' ? 1 : 2,
16920 if (cap = this.rules.hr.exec(src)) {
16921 src = src.substring(cap[0].length);
16929 if (cap = this.rules.blockquote.exec(src)) {
16930 src = src.substring(cap[0].length);
16933 type: 'blockquote_start'
16936 cap = cap[0].replace(/^ *> ?/gm, '');
16938 // Pass `top` to keep the current
16939 // "toplevel" state. This is exactly
16940 // how markdown.pl works.
16941 this.token(cap, top, true);
16944 type: 'blockquote_end'
16951 if (cap = this.rules.list.exec(src)) {
16952 src = src.substring(cap[0].length);
16956 type: 'list_start',
16957 ordered: bull.length > 1
16960 // Get each top-level item.
16961 cap = cap[0].match(this.rules.item);
16967 for (; i < l; i++) {
16970 // Remove the list item's bullet
16971 // so it is seen as the next token.
16972 space = item.length;
16973 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16975 // Outdent whatever the
16976 // list item contains. Hacky.
16977 if (~item.indexOf('\n ')) {
16978 space -= item.length;
16979 item = !this.options.pedantic
16980 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16981 : item.replace(/^ {1,4}/gm, '');
16984 // Determine whether the next list item belongs here.
16985 // Backpedal if it does not belong in this list.
16986 if (this.options.smartLists && i !== l - 1) {
16987 b = block.bullet.exec(cap[i + 1])[0];
16988 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16989 src = cap.slice(i + 1).join('\n') + src;
16994 // Determine whether item is loose or not.
16995 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16996 // for discount behavior.
16997 loose = next || /\n\n(?!\s*$)/.test(item);
16999 next = item.charAt(item.length - 1) === '\n';
17000 if (!loose) { loose = next; }
17005 ? 'loose_item_start'
17006 : 'list_item_start'
17010 this.token(item, false, bq);
17013 type: 'list_item_end'
17025 if (cap = this.rules.html.exec(src)) {
17026 src = src.substring(cap[0].length);
17028 type: this.options.sanitize
17031 pre: !this.options.sanitizer
17032 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17039 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17040 src = src.substring(cap[0].length);
17041 this.tokens.links[cap[1].toLowerCase()] = {
17049 if (top && (cap = this.rules.table.exec(src))) {
17050 src = src.substring(cap[0].length);
17054 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17055 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17056 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17059 for (i = 0; i < item.align.length; i++) {
17060 if (/^ *-+: *$/.test(item.align[i])) {
17061 item.align[i] = 'right';
17062 } else if (/^ *:-+: *$/.test(item.align[i])) {
17063 item.align[i] = 'center';
17064 } else if (/^ *:-+ *$/.test(item.align[i])) {
17065 item.align[i] = 'left';
17067 item.align[i] = null;
17071 for (i = 0; i < item.cells.length; i++) {
17072 item.cells[i] = item.cells[i]
17073 .replace(/^ *\| *| *\| *$/g, '')
17077 this.tokens.push(item);
17082 // top-level paragraph
17083 if (top && (cap = this.rules.paragraph.exec(src))) {
17084 src = src.substring(cap[0].length);
17087 text: cap[1].charAt(cap[1].length - 1) === '\n'
17088 ? cap[1].slice(0, -1)
17095 if (cap = this.rules.text.exec(src)) {
17096 // Top-level should never reach here.
17097 src = src.substring(cap[0].length);
17107 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17111 return this.tokens;
17115 * Inline-Level Grammar
17119 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17120 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17122 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17123 link: /^!?\[(inside)\]\(href\)/,
17124 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17125 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17126 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17127 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17128 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17129 br: /^ {2,}\n(?!\s*$)/,
17131 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17134 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17135 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17137 inline.link = replace(inline.link)
17138 ('inside', inline._inside)
17139 ('href', inline._href)
17142 inline.reflink = replace(inline.reflink)
17143 ('inside', inline._inside)
17147 * Normal Inline Grammar
17150 inline.normal = merge({}, inline);
17153 * Pedantic Inline Grammar
17156 inline.pedantic = merge({}, inline.normal, {
17157 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17158 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17162 * GFM Inline Grammar
17165 inline.gfm = merge({}, inline.normal, {
17166 escape: replace(inline.escape)('])', '~|])')(),
17167 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17168 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17169 text: replace(inline.text)
17171 ('|', '|https?://|')
17176 * GFM + Line Breaks Inline Grammar
17179 inline.breaks = merge({}, inline.gfm, {
17180 br: replace(inline.br)('{2,}', '*')(),
17181 text: replace(inline.gfm.text)('{2,}', '*')()
17185 * Inline Lexer & Compiler
17188 function InlineLexer(links, options) {
17189 this.options = options || marked.defaults;
17190 this.links = links;
17191 this.rules = inline.normal;
17192 this.renderer = this.options.renderer || new Renderer;
17193 this.renderer.options = this.options;
17197 Error('Tokens array requires a `links` property.');
17200 if (this.options.gfm) {
17201 if (this.options.breaks) {
17202 this.rules = inline.breaks;
17204 this.rules = inline.gfm;
17206 } else if (this.options.pedantic) {
17207 this.rules = inline.pedantic;
17212 * Expose Inline Rules
17215 InlineLexer.rules = inline;
17218 * Static Lexing/Compiling Method
17221 InlineLexer.output = function(src, links, options) {
17222 var inline = new InlineLexer(links, options);
17223 return inline.output(src);
17230 InlineLexer.prototype.output = function(src) {
17239 if (cap = this.rules.escape.exec(src)) {
17240 src = src.substring(cap[0].length);
17246 if (cap = this.rules.autolink.exec(src)) {
17247 src = src.substring(cap[0].length);
17248 if (cap[2] === '@') {
17249 text = cap[1].charAt(6) === ':'
17250 ? this.mangle(cap[1].substring(7))
17251 : this.mangle(cap[1]);
17252 href = this.mangle('mailto:') + text;
17254 text = escape(cap[1]);
17257 out += this.renderer.link(href, null, text);
17262 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17263 src = src.substring(cap[0].length);
17264 text = escape(cap[1]);
17266 out += this.renderer.link(href, null, text);
17271 if (cap = this.rules.tag.exec(src)) {
17272 if (!this.inLink && /^<a /i.test(cap[0])) {
17273 this.inLink = true;
17274 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17275 this.inLink = false;
17277 src = src.substring(cap[0].length);
17278 out += this.options.sanitize
17279 ? this.options.sanitizer
17280 ? this.options.sanitizer(cap[0])
17287 if (cap = this.rules.link.exec(src)) {
17288 src = src.substring(cap[0].length);
17289 this.inLink = true;
17290 out += this.outputLink(cap, {
17294 this.inLink = false;
17299 if ((cap = this.rules.reflink.exec(src))
17300 || (cap = this.rules.nolink.exec(src))) {
17301 src = src.substring(cap[0].length);
17302 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17303 link = this.links[link.toLowerCase()];
17304 if (!link || !link.href) {
17305 out += cap[0].charAt(0);
17306 src = cap[0].substring(1) + src;
17309 this.inLink = true;
17310 out += this.outputLink(cap, link);
17311 this.inLink = false;
17316 if (cap = this.rules.strong.exec(src)) {
17317 src = src.substring(cap[0].length);
17318 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17323 if (cap = this.rules.em.exec(src)) {
17324 src = src.substring(cap[0].length);
17325 out += this.renderer.em(this.output(cap[2] || cap[1]));
17330 if (cap = this.rules.code.exec(src)) {
17331 src = src.substring(cap[0].length);
17332 out += this.renderer.codespan(escape(cap[2], true));
17337 if (cap = this.rules.br.exec(src)) {
17338 src = src.substring(cap[0].length);
17339 out += this.renderer.br();
17344 if (cap = this.rules.del.exec(src)) {
17345 src = src.substring(cap[0].length);
17346 out += this.renderer.del(this.output(cap[1]));
17351 if (cap = this.rules.text.exec(src)) {
17352 src = src.substring(cap[0].length);
17353 out += this.renderer.text(escape(this.smartypants(cap[0])));
17359 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17370 InlineLexer.prototype.outputLink = function(cap, link) {
17371 var href = escape(link.href)
17372 , title = link.title ? escape(link.title) : null;
17374 return cap[0].charAt(0) !== '!'
17375 ? this.renderer.link(href, title, this.output(cap[1]))
17376 : this.renderer.image(href, title, escape(cap[1]));
17380 * Smartypants Transformations
17383 InlineLexer.prototype.smartypants = function(text) {
17384 if (!this.options.smartypants) { return text; }
17387 .replace(/---/g, '\u2014')
17389 .replace(/--/g, '\u2013')
17391 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17392 // closing singles & apostrophes
17393 .replace(/'/g, '\u2019')
17395 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17397 .replace(/"/g, '\u201d')
17399 .replace(/\.{3}/g, '\u2026');
17406 InlineLexer.prototype.mangle = function(text) {
17407 if (!this.options.mangle) { return text; }
17413 for (; i < l; i++) {
17414 ch = text.charCodeAt(i);
17415 if (Math.random() > 0.5) {
17416 ch = 'x' + ch.toString(16);
17418 out += '&#' + ch + ';';
17428 function Renderer(options) {
17429 this.options = options || {};
17432 Renderer.prototype.code = function(code, lang, escaped) {
17433 if (this.options.highlight) {
17434 var out = this.options.highlight(code, lang);
17435 if (out != null && out !== code) {
17440 // hack!!! - it's already escapeD?
17445 return '<pre><code>'
17446 + (escaped ? code : escape(code, true))
17447 + '\n</code></pre>';
17450 return '<pre><code class="'
17451 + this.options.langPrefix
17452 + escape(lang, true)
17454 + (escaped ? code : escape(code, true))
17455 + '\n</code></pre>\n';
17458 Renderer.prototype.blockquote = function(quote) {
17459 return '<blockquote>\n' + quote + '</blockquote>\n';
17462 Renderer.prototype.html = function(html) {
17466 Renderer.prototype.heading = function(text, level, raw) {
17470 + this.options.headerPrefix
17471 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17479 Renderer.prototype.hr = function() {
17480 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17483 Renderer.prototype.list = function(body, ordered) {
17484 var type = ordered ? 'ol' : 'ul';
17485 return '<' + type + '>\n' + body + '</' + type + '>\n';
17488 Renderer.prototype.listitem = function(text) {
17489 return '<li>' + text + '</li>\n';
17492 Renderer.prototype.paragraph = function(text) {
17493 return '<p>' + text + '</p>\n';
17496 Renderer.prototype.table = function(header, body) {
17497 return '<table class="table table-striped">\n'
17507 Renderer.prototype.tablerow = function(content) {
17508 return '<tr>\n' + content + '</tr>\n';
17511 Renderer.prototype.tablecell = function(content, flags) {
17512 var type = flags.header ? 'th' : 'td';
17513 var tag = flags.align
17514 ? '<' + type + ' style="text-align:' + flags.align + '">'
17515 : '<' + type + '>';
17516 return tag + content + '</' + type + '>\n';
17519 // span level renderer
17520 Renderer.prototype.strong = function(text) {
17521 return '<strong>' + text + '</strong>';
17524 Renderer.prototype.em = function(text) {
17525 return '<em>' + text + '</em>';
17528 Renderer.prototype.codespan = function(text) {
17529 return '<code>' + text + '</code>';
17532 Renderer.prototype.br = function() {
17533 return this.options.xhtml ? '<br/>' : '<br>';
17536 Renderer.prototype.del = function(text) {
17537 return '<del>' + text + '</del>';
17540 Renderer.prototype.link = function(href, title, text) {
17541 if (this.options.sanitize) {
17543 var prot = decodeURIComponent(unescape(href))
17544 .replace(/[^\w:]/g, '')
17549 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17553 var out = '<a href="' + href + '"';
17555 out += ' title="' + title + '"';
17557 out += '>' + text + '</a>';
17561 Renderer.prototype.image = function(href, title, text) {
17562 var out = '<img src="' + href + '" alt="' + text + '"';
17564 out += ' title="' + title + '"';
17566 out += this.options.xhtml ? '/>' : '>';
17570 Renderer.prototype.text = function(text) {
17575 * Parsing & Compiling
17578 function Parser(options) {
17581 this.options = options || marked.defaults;
17582 this.options.renderer = this.options.renderer || new Renderer;
17583 this.renderer = this.options.renderer;
17584 this.renderer.options = this.options;
17588 * Static Parse Method
17591 Parser.parse = function(src, options, renderer) {
17592 var parser = new Parser(options, renderer);
17593 return parser.parse(src);
17600 Parser.prototype.parse = function(src) {
17601 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17602 this.tokens = src.reverse();
17605 while (this.next()) {
17616 Parser.prototype.next = function() {
17617 return this.token = this.tokens.pop();
17621 * Preview Next Token
17624 Parser.prototype.peek = function() {
17625 return this.tokens[this.tokens.length - 1] || 0;
17629 * Parse Text Tokens
17632 Parser.prototype.parseText = function() {
17633 var body = this.token.text;
17635 while (this.peek().type === 'text') {
17636 body += '\n' + this.next().text;
17639 return this.inline.output(body);
17643 * Parse Current Token
17646 Parser.prototype.tok = function() {
17647 switch (this.token.type) {
17652 return this.renderer.hr();
17655 return this.renderer.heading(
17656 this.inline.output(this.token.text),
17661 return this.renderer.code(this.token.text,
17663 this.token.escaped);
17676 for (i = 0; i < this.token.header.length; i++) {
17677 flags = { header: true, align: this.token.align[i] };
17678 cell += this.renderer.tablecell(
17679 this.inline.output(this.token.header[i]),
17680 { header: true, align: this.token.align[i] }
17683 header += this.renderer.tablerow(cell);
17685 for (i = 0; i < this.token.cells.length; i++) {
17686 row = this.token.cells[i];
17689 for (j = 0; j < row.length; j++) {
17690 cell += this.renderer.tablecell(
17691 this.inline.output(row[j]),
17692 { header: false, align: this.token.align[j] }
17696 body += this.renderer.tablerow(cell);
17698 return this.renderer.table(header, body);
17700 case 'blockquote_start': {
17703 while (this.next().type !== 'blockquote_end') {
17704 body += this.tok();
17707 return this.renderer.blockquote(body);
17709 case 'list_start': {
17711 , ordered = this.token.ordered;
17713 while (this.next().type !== 'list_end') {
17714 body += this.tok();
17717 return this.renderer.list(body, ordered);
17719 case 'list_item_start': {
17722 while (this.next().type !== 'list_item_end') {
17723 body += this.token.type === 'text'
17728 return this.renderer.listitem(body);
17730 case 'loose_item_start': {
17733 while (this.next().type !== 'list_item_end') {
17734 body += this.tok();
17737 return this.renderer.listitem(body);
17740 var html = !this.token.pre && !this.options.pedantic
17741 ? this.inline.output(this.token.text)
17743 return this.renderer.html(html);
17745 case 'paragraph': {
17746 return this.renderer.paragraph(this.inline.output(this.token.text));
17749 return this.renderer.paragraph(this.parseText());
17758 function escape(html, encode) {
17760 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17761 .replace(/</g, '<')
17762 .replace(/>/g, '>')
17763 .replace(/"/g, '"')
17764 .replace(/'/g, ''');
17767 function unescape(html) {
17768 // explicitly match decimal, hex, and named HTML entities
17769 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17770 n = n.toLowerCase();
17771 if (n === 'colon') { return ':'; }
17772 if (n.charAt(0) === '#') {
17773 return n.charAt(1) === 'x'
17774 ? String.fromCharCode(parseInt(n.substring(2), 16))
17775 : String.fromCharCode(+n.substring(1));
17781 function replace(regex, opt) {
17782 regex = regex.source;
17784 return function self(name, val) {
17785 if (!name) { return new RegExp(regex, opt); }
17786 val = val.source || val;
17787 val = val.replace(/(^|[^\[])\^/g, '$1');
17788 regex = regex.replace(name, val);
17796 function merge(obj) {
17801 for (; i < arguments.length; i++) {
17802 target = arguments[i];
17803 for (key in target) {
17804 if (Object.prototype.hasOwnProperty.call(target, key)) {
17805 obj[key] = target[key];
17818 function marked(src, opt, callback) {
17819 if (callback || typeof opt === 'function') {
17825 opt = merge({}, marked.defaults, opt || {});
17827 var highlight = opt.highlight
17833 tokens = Lexer.lex(src, opt)
17835 return callback(e);
17838 pending = tokens.length;
17840 var done = function(err) {
17842 opt.highlight = highlight;
17843 return callback(err);
17849 out = Parser.parse(tokens, opt);
17854 opt.highlight = highlight;
17858 : callback(null, out);
17861 if (!highlight || highlight.length < 3) {
17865 delete opt.highlight;
17867 if (!pending) { return done(); }
17869 for (; i < tokens.length; i++) {
17871 if (token.type !== 'code') {
17872 return --pending || done();
17874 return highlight(token.text, token.lang, function(err, code) {
17875 if (err) { return done(err); }
17876 if (code == null || code === token.text) {
17877 return --pending || done();
17880 token.escaped = true;
17881 --pending || done();
17889 if (opt) { opt = merge({}, marked.defaults, opt); }
17890 return Parser.parse(Lexer.lex(src, opt), opt);
17892 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17893 if ((opt || marked.defaults).silent) {
17894 return '<p>An error occured:</p><pre>'
17895 + escape(e.message + '', true)
17907 marked.setOptions = function(opt) {
17908 merge(marked.defaults, opt);
17912 marked.defaults = {
17923 langPrefix: 'lang-',
17924 smartypants: false,
17926 renderer: new Renderer,
17934 marked.Parser = Parser;
17935 marked.parser = Parser.parse;
17937 marked.Renderer = Renderer;
17939 marked.Lexer = Lexer;
17940 marked.lexer = Lexer.lex;
17942 marked.InlineLexer = InlineLexer;
17943 marked.inlineLexer = InlineLexer.output;
17945 marked.parse = marked;
17947 Roo.Markdown.marked = marked;
17951 * Ext JS Library 1.1.1
17952 * Copyright(c) 2006-2007, Ext JS, LLC.
17954 * Originally Released Under LGPL - original licence link has changed is not relivant.
17957 * <script type="text/javascript">
17963 * These classes are derivatives of the similarly named classes in the YUI Library.
17964 * The original license:
17965 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17966 * Code licensed under the BSD License:
17967 * http://developer.yahoo.net/yui/license.txt
17972 var Event=Roo.EventManager;
17973 var Dom=Roo.lib.Dom;
17976 * @class Roo.dd.DragDrop
17977 * @extends Roo.util.Observable
17978 * Defines the interface and base operation of items that that can be
17979 * dragged or can be drop targets. It was designed to be extended, overriding
17980 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17981 * Up to three html elements can be associated with a DragDrop instance:
17983 * <li>linked element: the element that is passed into the constructor.
17984 * This is the element which defines the boundaries for interaction with
17985 * other DragDrop objects.</li>
17986 * <li>handle element(s): The drag operation only occurs if the element that
17987 * was clicked matches a handle element. By default this is the linked
17988 * element, but there are times that you will want only a portion of the
17989 * linked element to initiate the drag operation, and the setHandleElId()
17990 * method provides a way to define this.</li>
17991 * <li>drag element: this represents the element that would be moved along
17992 * with the cursor during a drag operation. By default, this is the linked
17993 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17994 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17997 * This class should not be instantiated until the onload event to ensure that
17998 * the associated elements are available.
17999 * The following would define a DragDrop obj that would interact with any
18000 * other DragDrop obj in the "group1" group:
18002 * dd = new Roo.dd.DragDrop("div1", "group1");
18004 * Since none of the event handlers have been implemented, nothing would
18005 * actually happen if you were to run the code above. Normally you would
18006 * override this class or one of the default implementations, but you can
18007 * also override the methods you want on an instance of the class...
18009 * dd.onDragDrop = function(e, id) {
18010 * alert("dd was dropped on " + id);
18014 * @param {String} id of the element that is linked to this instance
18015 * @param {String} sGroup the group of related DragDrop objects
18016 * @param {object} config an object containing configurable attributes
18017 * Valid properties for DragDrop:
18018 * padding, isTarget, maintainOffset, primaryButtonOnly
18020 Roo.dd.DragDrop = function(id, sGroup, config) {
18022 this.init(id, sGroup, config);
18027 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18030 * The id of the element associated with this object. This is what we
18031 * refer to as the "linked element" because the size and position of
18032 * this element is used to determine when the drag and drop objects have
18040 * Configuration attributes passed into the constructor
18047 * The id of the element that will be dragged. By default this is same
18048 * as the linked element , but could be changed to another element. Ex:
18050 * @property dragElId
18057 * the id of the element that initiates the drag operation. By default
18058 * this is the linked element, but could be changed to be a child of this
18059 * element. This lets us do things like only starting the drag when the
18060 * header element within the linked html element is clicked.
18061 * @property handleElId
18068 * An associative array of HTML tags that will be ignored if clicked.
18069 * @property invalidHandleTypes
18070 * @type {string: string}
18072 invalidHandleTypes: null,
18075 * An associative array of ids for elements that will be ignored if clicked
18076 * @property invalidHandleIds
18077 * @type {string: string}
18079 invalidHandleIds: null,
18082 * An indexted array of css class names for elements that will be ignored
18084 * @property invalidHandleClasses
18087 invalidHandleClasses: null,
18090 * The linked element's absolute X position at the time the drag was
18092 * @property startPageX
18099 * The linked element's absolute X position at the time the drag was
18101 * @property startPageY
18108 * The group defines a logical collection of DragDrop objects that are
18109 * related. Instances only get events when interacting with other
18110 * DragDrop object in the same group. This lets us define multiple
18111 * groups using a single DragDrop subclass if we want.
18113 * @type {string: string}
18118 * Individual drag/drop instances can be locked. This will prevent
18119 * onmousedown start drag.
18127 * Lock this instance
18130 lock: function() { this.locked = true; },
18133 * Unlock this instace
18136 unlock: function() { this.locked = false; },
18139 * By default, all insances can be a drop target. This can be disabled by
18140 * setting isTarget to false.
18147 * The padding configured for this drag and drop object for calculating
18148 * the drop zone intersection with this object.
18155 * Cached reference to the linked element
18156 * @property _domRef
18162 * Internal typeof flag
18163 * @property __ygDragDrop
18166 __ygDragDrop: true,
18169 * Set to true when horizontal contraints are applied
18170 * @property constrainX
18177 * Set to true when vertical contraints are applied
18178 * @property constrainY
18185 * The left constraint
18193 * The right constraint
18201 * The up constraint
18210 * The down constraint
18218 * Maintain offsets when we resetconstraints. Set to true when you want
18219 * the position of the element relative to its parent to stay the same
18220 * when the page changes
18222 * @property maintainOffset
18225 maintainOffset: false,
18228 * Array of pixel locations the element will snap to if we specified a
18229 * horizontal graduation/interval. This array is generated automatically
18230 * when you define a tick interval.
18237 * Array of pixel locations the element will snap to if we specified a
18238 * vertical graduation/interval. This array is generated automatically
18239 * when you define a tick interval.
18246 * By default the drag and drop instance will only respond to the primary
18247 * button click (left button for a right-handed mouse). Set to true to
18248 * allow drag and drop to start with any mouse click that is propogated
18250 * @property primaryButtonOnly
18253 primaryButtonOnly: true,
18256 * The availabe property is false until the linked dom element is accessible.
18257 * @property available
18263 * By default, drags can only be initiated if the mousedown occurs in the
18264 * region the linked element is. This is done in part to work around a
18265 * bug in some browsers that mis-report the mousedown if the previous
18266 * mouseup happened outside of the window. This property is set to true
18267 * if outer handles are defined.
18269 * @property hasOuterHandles
18273 hasOuterHandles: false,
18276 * Code that executes immediately before the startDrag event
18277 * @method b4StartDrag
18280 b4StartDrag: function(x, y) { },
18283 * Abstract method called after a drag/drop object is clicked
18284 * and the drag or mousedown time thresholds have beeen met.
18285 * @method startDrag
18286 * @param {int} X click location
18287 * @param {int} Y click location
18289 startDrag: function(x, y) { /* override this */ },
18292 * Code that executes immediately before the onDrag event
18296 b4Drag: function(e) { },
18299 * Abstract method called during the onMouseMove event while dragging an
18302 * @param {Event} e the mousemove event
18304 onDrag: function(e) { /* override this */ },
18307 * Abstract method called when this element fist begins hovering over
18308 * another DragDrop obj
18309 * @method onDragEnter
18310 * @param {Event} e the mousemove event
18311 * @param {String|DragDrop[]} id In POINT mode, the element
18312 * id this is hovering over. In INTERSECT mode, an array of one or more
18313 * dragdrop items being hovered over.
18315 onDragEnter: function(e, id) { /* override this */ },
18318 * Code that executes immediately before the onDragOver event
18319 * @method b4DragOver
18322 b4DragOver: function(e) { },
18325 * Abstract method called when this element is hovering over another
18327 * @method onDragOver
18328 * @param {Event} e the mousemove event
18329 * @param {String|DragDrop[]} id In POINT mode, the element
18330 * id this is hovering over. In INTERSECT mode, an array of dd items
18331 * being hovered over.
18333 onDragOver: function(e, id) { /* override this */ },
18336 * Code that executes immediately before the onDragOut event
18337 * @method b4DragOut
18340 b4DragOut: function(e) { },
18343 * Abstract method called when we are no longer hovering over an element
18344 * @method onDragOut
18345 * @param {Event} e the mousemove event
18346 * @param {String|DragDrop[]} id In POINT mode, the element
18347 * id this was hovering over. In INTERSECT mode, an array of dd items
18348 * that the mouse is no longer over.
18350 onDragOut: function(e, id) { /* override this */ },
18353 * Code that executes immediately before the onDragDrop event
18354 * @method b4DragDrop
18357 b4DragDrop: function(e) { },
18360 * Abstract method called when this item is dropped on another DragDrop
18362 * @method onDragDrop
18363 * @param {Event} e the mouseup event
18364 * @param {String|DragDrop[]} id In POINT mode, the element
18365 * id this was dropped on. In INTERSECT mode, an array of dd items this
18368 onDragDrop: function(e, id) { /* override this */ },
18371 * Abstract method called when this item is dropped on an area with no
18373 * @method onInvalidDrop
18374 * @param {Event} e the mouseup event
18376 onInvalidDrop: function(e) { /* override this */ },
18379 * Code that executes immediately before the endDrag event
18380 * @method b4EndDrag
18383 b4EndDrag: function(e) { },
18386 * Fired when we are done dragging the object
18388 * @param {Event} e the mouseup event
18390 endDrag: function(e) { /* override this */ },
18393 * Code executed immediately before the onMouseDown event
18394 * @method b4MouseDown
18395 * @param {Event} e the mousedown event
18398 b4MouseDown: function(e) { },
18401 * Event handler that fires when a drag/drop obj gets a mousedown
18402 * @method onMouseDown
18403 * @param {Event} e the mousedown event
18405 onMouseDown: function(e) { /* override this */ },
18408 * Event handler that fires when a drag/drop obj gets a mouseup
18409 * @method onMouseUp
18410 * @param {Event} e the mouseup event
18412 onMouseUp: function(e) { /* override this */ },
18415 * Override the onAvailable method to do what is needed after the initial
18416 * position was determined.
18417 * @method onAvailable
18419 onAvailable: function () {
18423 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18426 defaultPadding : {left:0, right:0, top:0, bottom:0},
18429 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18433 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18434 { dragElId: "existingProxyDiv" });
18435 dd.startDrag = function(){
18436 this.constrainTo("parent-id");
18439 * Or you can initalize it using the {@link Roo.Element} object:
18441 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18442 startDrag : function(){
18443 this.constrainTo("parent-id");
18447 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18448 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18449 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18450 * an object containing the sides to pad. For example: {right:10, bottom:10}
18451 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18453 constrainTo : function(constrainTo, pad, inContent){
18454 if(typeof pad == "number"){
18455 pad = {left: pad, right:pad, top:pad, bottom:pad};
18457 pad = pad || this.defaultPadding;
18458 var b = Roo.get(this.getEl()).getBox();
18459 var ce = Roo.get(constrainTo);
18460 var s = ce.getScroll();
18461 var c, cd = ce.dom;
18462 if(cd == document.body){
18463 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18466 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18470 var topSpace = b.y - c.y;
18471 var leftSpace = b.x - c.x;
18473 this.resetConstraints();
18474 this.setXConstraint(leftSpace - (pad.left||0), // left
18475 c.width - leftSpace - b.width - (pad.right||0) //right
18477 this.setYConstraint(topSpace - (pad.top||0), //top
18478 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18483 * Returns a reference to the linked element
18485 * @return {HTMLElement} the html element
18487 getEl: function() {
18488 if (!this._domRef) {
18489 this._domRef = Roo.getDom(this.id);
18492 return this._domRef;
18496 * Returns a reference to the actual element to drag. By default this is
18497 * the same as the html element, but it can be assigned to another
18498 * element. An example of this can be found in Roo.dd.DDProxy
18499 * @method getDragEl
18500 * @return {HTMLElement} the html element
18502 getDragEl: function() {
18503 return Roo.getDom(this.dragElId);
18507 * Sets up the DragDrop object. Must be called in the constructor of any
18508 * Roo.dd.DragDrop subclass
18510 * @param id the id of the linked element
18511 * @param {String} sGroup the group of related items
18512 * @param {object} config configuration attributes
18514 init: function(id, sGroup, config) {
18515 this.initTarget(id, sGroup, config);
18516 if (!Roo.isTouch) {
18517 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18519 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18520 // Event.on(this.id, "selectstart", Event.preventDefault);
18524 * Initializes Targeting functionality only... the object does not
18525 * get a mousedown handler.
18526 * @method initTarget
18527 * @param id the id of the linked element
18528 * @param {String} sGroup the group of related items
18529 * @param {object} config configuration attributes
18531 initTarget: function(id, sGroup, config) {
18533 // configuration attributes
18534 this.config = config || {};
18536 // create a local reference to the drag and drop manager
18537 this.DDM = Roo.dd.DDM;
18538 // initialize the groups array
18541 // assume that we have an element reference instead of an id if the
18542 // parameter is not a string
18543 if (typeof id !== "string") {
18550 // add to an interaction group
18551 this.addToGroup((sGroup) ? sGroup : "default");
18553 // We don't want to register this as the handle with the manager
18554 // so we just set the id rather than calling the setter.
18555 this.handleElId = id;
18557 // the linked element is the element that gets dragged by default
18558 this.setDragElId(id);
18560 // by default, clicked anchors will not start drag operations.
18561 this.invalidHandleTypes = { A: "A" };
18562 this.invalidHandleIds = {};
18563 this.invalidHandleClasses = [];
18565 this.applyConfig();
18567 this.handleOnAvailable();
18571 * Applies the configuration parameters that were passed into the constructor.
18572 * This is supposed to happen at each level through the inheritance chain. So
18573 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18574 * DragDrop in order to get all of the parameters that are available in
18576 * @method applyConfig
18578 applyConfig: function() {
18580 // configurable properties:
18581 // padding, isTarget, maintainOffset, primaryButtonOnly
18582 this.padding = this.config.padding || [0, 0, 0, 0];
18583 this.isTarget = (this.config.isTarget !== false);
18584 this.maintainOffset = (this.config.maintainOffset);
18585 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18590 * Executed when the linked element is available
18591 * @method handleOnAvailable
18594 handleOnAvailable: function() {
18595 this.available = true;
18596 this.resetConstraints();
18597 this.onAvailable();
18601 * Configures the padding for the target zone in px. Effectively expands
18602 * (or reduces) the virtual object size for targeting calculations.
18603 * Supports css-style shorthand; if only one parameter is passed, all sides
18604 * will have that padding, and if only two are passed, the top and bottom
18605 * will have the first param, the left and right the second.
18606 * @method setPadding
18607 * @param {int} iTop Top pad
18608 * @param {int} iRight Right pad
18609 * @param {int} iBot Bot pad
18610 * @param {int} iLeft Left pad
18612 setPadding: function(iTop, iRight, iBot, iLeft) {
18613 // this.padding = [iLeft, iRight, iTop, iBot];
18614 if (!iRight && 0 !== iRight) {
18615 this.padding = [iTop, iTop, iTop, iTop];
18616 } else if (!iBot && 0 !== iBot) {
18617 this.padding = [iTop, iRight, iTop, iRight];
18619 this.padding = [iTop, iRight, iBot, iLeft];
18624 * Stores the initial placement of the linked element.
18625 * @method setInitialPosition
18626 * @param {int} diffX the X offset, default 0
18627 * @param {int} diffY the Y offset, default 0
18629 setInitPosition: function(diffX, diffY) {
18630 var el = this.getEl();
18632 if (!this.DDM.verifyEl(el)) {
18636 var dx = diffX || 0;
18637 var dy = diffY || 0;
18639 var p = Dom.getXY( el );
18641 this.initPageX = p[0] - dx;
18642 this.initPageY = p[1] - dy;
18644 this.lastPageX = p[0];
18645 this.lastPageY = p[1];
18648 this.setStartPosition(p);
18652 * Sets the start position of the element. This is set when the obj
18653 * is initialized, the reset when a drag is started.
18654 * @method setStartPosition
18655 * @param pos current position (from previous lookup)
18658 setStartPosition: function(pos) {
18659 var p = pos || Dom.getXY( this.getEl() );
18660 this.deltaSetXY = null;
18662 this.startPageX = p[0];
18663 this.startPageY = p[1];
18667 * Add this instance to a group of related drag/drop objects. All
18668 * instances belong to at least one group, and can belong to as many
18669 * groups as needed.
18670 * @method addToGroup
18671 * @param sGroup {string} the name of the group
18673 addToGroup: function(sGroup) {
18674 this.groups[sGroup] = true;
18675 this.DDM.regDragDrop(this, sGroup);
18679 * Remove's this instance from the supplied interaction group
18680 * @method removeFromGroup
18681 * @param {string} sGroup The group to drop
18683 removeFromGroup: function(sGroup) {
18684 if (this.groups[sGroup]) {
18685 delete this.groups[sGroup];
18688 this.DDM.removeDDFromGroup(this, sGroup);
18692 * Allows you to specify that an element other than the linked element
18693 * will be moved with the cursor during a drag
18694 * @method setDragElId
18695 * @param id {string} the id of the element that will be used to initiate the drag
18697 setDragElId: function(id) {
18698 this.dragElId = id;
18702 * Allows you to specify a child of the linked element that should be
18703 * used to initiate the drag operation. An example of this would be if
18704 * you have a content div with text and links. Clicking anywhere in the
18705 * content area would normally start the drag operation. Use this method
18706 * to specify that an element inside of the content div is the element
18707 * that starts the drag operation.
18708 * @method setHandleElId
18709 * @param id {string} the id of the element that will be used to
18710 * initiate the drag.
18712 setHandleElId: function(id) {
18713 if (typeof id !== "string") {
18716 this.handleElId = id;
18717 this.DDM.regHandle(this.id, id);
18721 * Allows you to set an element outside of the linked element as a drag
18723 * @method setOuterHandleElId
18724 * @param id the id of the element that will be used to initiate the drag
18726 setOuterHandleElId: function(id) {
18727 if (typeof id !== "string") {
18730 Event.on(id, "mousedown",
18731 this.handleMouseDown, this);
18732 this.setHandleElId(id);
18734 this.hasOuterHandles = true;
18738 * Remove all drag and drop hooks for this element
18741 unreg: function() {
18742 Event.un(this.id, "mousedown",
18743 this.handleMouseDown);
18744 Event.un(this.id, "touchstart",
18745 this.handleMouseDown);
18746 this._domRef = null;
18747 this.DDM._remove(this);
18750 destroy : function(){
18755 * Returns true if this instance is locked, or the drag drop mgr is locked
18756 * (meaning that all drag/drop is disabled on the page.)
18758 * @return {boolean} true if this obj or all drag/drop is locked, else
18761 isLocked: function() {
18762 return (this.DDM.isLocked() || this.locked);
18766 * Fired when this object is clicked
18767 * @method handleMouseDown
18769 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18772 handleMouseDown: function(e, oDD){
18774 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18775 //Roo.log('not touch/ button !=0');
18778 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18779 return; // double touch..
18783 if (this.isLocked()) {
18784 //Roo.log('locked');
18788 this.DDM.refreshCache(this.groups);
18789 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18790 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18791 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18792 //Roo.log('no outer handes or not over target');
18795 // Roo.log('check validator');
18796 if (this.clickValidator(e)) {
18797 // Roo.log('validate success');
18798 // set the initial element position
18799 this.setStartPosition();
18802 this.b4MouseDown(e);
18803 this.onMouseDown(e);
18805 this.DDM.handleMouseDown(e, this);
18807 this.DDM.stopEvent(e);
18815 clickValidator: function(e) {
18816 var target = e.getTarget();
18817 return ( this.isValidHandleChild(target) &&
18818 (this.id == this.handleElId ||
18819 this.DDM.handleWasClicked(target, this.id)) );
18823 * Allows you to specify a tag name that should not start a drag operation
18824 * when clicked. This is designed to facilitate embedding links within a
18825 * drag handle that do something other than start the drag.
18826 * @method addInvalidHandleType
18827 * @param {string} tagName the type of element to exclude
18829 addInvalidHandleType: function(tagName) {
18830 var type = tagName.toUpperCase();
18831 this.invalidHandleTypes[type] = type;
18835 * Lets you to specify an element id for a child of a drag handle
18836 * that should not initiate a drag
18837 * @method addInvalidHandleId
18838 * @param {string} id the element id of the element you wish to ignore
18840 addInvalidHandleId: function(id) {
18841 if (typeof id !== "string") {
18844 this.invalidHandleIds[id] = id;
18848 * Lets you specify a css class of elements that will not initiate a drag
18849 * @method addInvalidHandleClass
18850 * @param {string} cssClass the class of the elements you wish to ignore
18852 addInvalidHandleClass: function(cssClass) {
18853 this.invalidHandleClasses.push(cssClass);
18857 * Unsets an excluded tag name set by addInvalidHandleType
18858 * @method removeInvalidHandleType
18859 * @param {string} tagName the type of element to unexclude
18861 removeInvalidHandleType: function(tagName) {
18862 var type = tagName.toUpperCase();
18863 // this.invalidHandleTypes[type] = null;
18864 delete this.invalidHandleTypes[type];
18868 * Unsets an invalid handle id
18869 * @method removeInvalidHandleId
18870 * @param {string} id the id of the element to re-enable
18872 removeInvalidHandleId: function(id) {
18873 if (typeof id !== "string") {
18876 delete this.invalidHandleIds[id];
18880 * Unsets an invalid css class
18881 * @method removeInvalidHandleClass
18882 * @param {string} cssClass the class of the element(s) you wish to
18885 removeInvalidHandleClass: function(cssClass) {
18886 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18887 if (this.invalidHandleClasses[i] == cssClass) {
18888 delete this.invalidHandleClasses[i];
18894 * Checks the tag exclusion list to see if this click should be ignored
18895 * @method isValidHandleChild
18896 * @param {HTMLElement} node the HTMLElement to evaluate
18897 * @return {boolean} true if this is a valid tag type, false if not
18899 isValidHandleChild: function(node) {
18902 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18905 nodeName = node.nodeName.toUpperCase();
18907 nodeName = node.nodeName;
18909 valid = valid && !this.invalidHandleTypes[nodeName];
18910 valid = valid && !this.invalidHandleIds[node.id];
18912 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18913 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18922 * Create the array of horizontal tick marks if an interval was specified
18923 * in setXConstraint().
18924 * @method setXTicks
18927 setXTicks: function(iStartX, iTickSize) {
18929 this.xTickSize = iTickSize;
18933 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18935 this.xTicks[this.xTicks.length] = i;
18940 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18942 this.xTicks[this.xTicks.length] = i;
18947 this.xTicks.sort(this.DDM.numericSort) ;
18951 * Create the array of vertical tick marks if an interval was specified in
18952 * setYConstraint().
18953 * @method setYTicks
18956 setYTicks: function(iStartY, iTickSize) {
18958 this.yTickSize = iTickSize;
18962 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18964 this.yTicks[this.yTicks.length] = i;
18969 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18971 this.yTicks[this.yTicks.length] = i;
18976 this.yTicks.sort(this.DDM.numericSort) ;
18980 * By default, the element can be dragged any place on the screen. Use
18981 * this method to limit the horizontal travel of the element. Pass in
18982 * 0,0 for the parameters if you want to lock the drag to the y axis.
18983 * @method setXConstraint
18984 * @param {int} iLeft the number of pixels the element can move to the left
18985 * @param {int} iRight the number of pixels the element can move to the
18987 * @param {int} iTickSize optional parameter for specifying that the
18989 * should move iTickSize pixels at a time.
18991 setXConstraint: function(iLeft, iRight, iTickSize) {
18992 this.leftConstraint = iLeft;
18993 this.rightConstraint = iRight;
18995 this.minX = this.initPageX - iLeft;
18996 this.maxX = this.initPageX + iRight;
18997 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18999 this.constrainX = true;
19003 * Clears any constraints applied to this instance. Also clears ticks
19004 * since they can't exist independent of a constraint at this time.
19005 * @method clearConstraints
19007 clearConstraints: function() {
19008 this.constrainX = false;
19009 this.constrainY = false;
19014 * Clears any tick interval defined for this instance
19015 * @method clearTicks
19017 clearTicks: function() {
19018 this.xTicks = null;
19019 this.yTicks = null;
19020 this.xTickSize = 0;
19021 this.yTickSize = 0;
19025 * By default, the element can be dragged any place on the screen. Set
19026 * this to limit the vertical travel of the element. Pass in 0,0 for the
19027 * parameters if you want to lock the drag to the x axis.
19028 * @method setYConstraint
19029 * @param {int} iUp the number of pixels the element can move up
19030 * @param {int} iDown the number of pixels the element can move down
19031 * @param {int} iTickSize optional parameter for specifying that the
19032 * element should move iTickSize pixels at a time.
19034 setYConstraint: function(iUp, iDown, iTickSize) {
19035 this.topConstraint = iUp;
19036 this.bottomConstraint = iDown;
19038 this.minY = this.initPageY - iUp;
19039 this.maxY = this.initPageY + iDown;
19040 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19042 this.constrainY = true;
19047 * resetConstraints must be called if you manually reposition a dd element.
19048 * @method resetConstraints
19049 * @param {boolean} maintainOffset
19051 resetConstraints: function() {
19054 // Maintain offsets if necessary
19055 if (this.initPageX || this.initPageX === 0) {
19056 // figure out how much this thing has moved
19057 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19058 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19060 this.setInitPosition(dx, dy);
19062 // This is the first time we have detected the element's position
19064 this.setInitPosition();
19067 if (this.constrainX) {
19068 this.setXConstraint( this.leftConstraint,
19069 this.rightConstraint,
19073 if (this.constrainY) {
19074 this.setYConstraint( this.topConstraint,
19075 this.bottomConstraint,
19081 * Normally the drag element is moved pixel by pixel, but we can specify
19082 * that it move a number of pixels at a time. This method resolves the
19083 * location when we have it set up like this.
19085 * @param {int} val where we want to place the object
19086 * @param {int[]} tickArray sorted array of valid points
19087 * @return {int} the closest tick
19090 getTick: function(val, tickArray) {
19093 // If tick interval is not defined, it is effectively 1 pixel,
19094 // so we return the value passed to us.
19096 } else if (tickArray[0] >= val) {
19097 // The value is lower than the first tick, so we return the first
19099 return tickArray[0];
19101 for (var i=0, len=tickArray.length; i<len; ++i) {
19103 if (tickArray[next] && tickArray[next] >= val) {
19104 var diff1 = val - tickArray[i];
19105 var diff2 = tickArray[next] - val;
19106 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19110 // The value is larger than the last tick, so we return the last
19112 return tickArray[tickArray.length - 1];
19119 * @return {string} string representation of the dd obj
19121 toString: function() {
19122 return ("DragDrop " + this.id);
19130 * Ext JS Library 1.1.1
19131 * Copyright(c) 2006-2007, Ext JS, LLC.
19133 * Originally Released Under LGPL - original licence link has changed is not relivant.
19136 * <script type="text/javascript">
19141 * The drag and drop utility provides a framework for building drag and drop
19142 * applications. In addition to enabling drag and drop for specific elements,
19143 * the drag and drop elements are tracked by the manager class, and the
19144 * interactions between the various elements are tracked during the drag and
19145 * the implementing code is notified about these important moments.
19148 // Only load the library once. Rewriting the manager class would orphan
19149 // existing drag and drop instances.
19150 if (!Roo.dd.DragDropMgr) {
19153 * @class Roo.dd.DragDropMgr
19154 * DragDropMgr is a singleton that tracks the element interaction for
19155 * all DragDrop items in the window. Generally, you will not call
19156 * this class directly, but it does have helper methods that could
19157 * be useful in your DragDrop implementations.
19160 Roo.dd.DragDropMgr = function() {
19162 var Event = Roo.EventManager;
19167 * Two dimensional Array of registered DragDrop objects. The first
19168 * dimension is the DragDrop item group, the second the DragDrop
19171 * @type {string: string}
19178 * Array of element ids defined as drag handles. Used to determine
19179 * if the element that generated the mousedown event is actually the
19180 * handle and not the html element itself.
19181 * @property handleIds
19182 * @type {string: string}
19189 * the DragDrop object that is currently being dragged
19190 * @property dragCurrent
19198 * the DragDrop object(s) that are being hovered over
19199 * @property dragOvers
19207 * the X distance between the cursor and the object being dragged
19216 * the Y distance between the cursor and the object being dragged
19225 * Flag to determine if we should prevent the default behavior of the
19226 * events we define. By default this is true, but this can be set to
19227 * false if you need the default behavior (not recommended)
19228 * @property preventDefault
19232 preventDefault: true,
19235 * Flag to determine if we should stop the propagation of the events
19236 * we generate. This is true by default but you may want to set it to
19237 * false if the html element contains other features that require the
19239 * @property stopPropagation
19243 stopPropagation: true,
19246 * Internal flag that is set to true when drag and drop has been
19248 * @property initialized
19255 * All drag and drop can be disabled.
19263 * Called the first time an element is registered.
19269 this.initialized = true;
19273 * In point mode, drag and drop interaction is defined by the
19274 * location of the cursor during the drag/drop
19282 * In intersect mode, drag and drop interactio nis defined by the
19283 * overlap of two or more drag and drop objects.
19284 * @property INTERSECT
19291 * The current drag and drop mode. Default: POINT
19299 * Runs method on all drag and drop objects
19300 * @method _execOnAll
19304 _execOnAll: function(sMethod, args) {
19305 for (var i in this.ids) {
19306 for (var j in this.ids[i]) {
19307 var oDD = this.ids[i][j];
19308 if (! this.isTypeOfDD(oDD)) {
19311 oDD[sMethod].apply(oDD, args);
19317 * Drag and drop initialization. Sets up the global event handlers
19322 _onLoad: function() {
19326 if (!Roo.isTouch) {
19327 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19328 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19330 Event.on(document, "touchend", this.handleMouseUp, this, true);
19331 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19333 Event.on(window, "unload", this._onUnload, this, true);
19334 Event.on(window, "resize", this._onResize, this, true);
19335 // Event.on(window, "mouseout", this._test);
19340 * Reset constraints on all drag and drop objs
19341 * @method _onResize
19345 _onResize: function(e) {
19346 this._execOnAll("resetConstraints", []);
19350 * Lock all drag and drop functionality
19354 lock: function() { this.locked = true; },
19357 * Unlock all drag and drop functionality
19361 unlock: function() { this.locked = false; },
19364 * Is drag and drop locked?
19366 * @return {boolean} True if drag and drop is locked, false otherwise.
19369 isLocked: function() { return this.locked; },
19372 * Location cache that is set for all drag drop objects when a drag is
19373 * initiated, cleared when the drag is finished.
19374 * @property locationCache
19381 * Set useCache to false if you want to force object the lookup of each
19382 * drag and drop linked element constantly during a drag.
19383 * @property useCache
19390 * The number of pixels that the mouse needs to move after the
19391 * mousedown before the drag is initiated. Default=3;
19392 * @property clickPixelThresh
19396 clickPixelThresh: 3,
19399 * The number of milliseconds after the mousedown event to initiate the
19400 * drag if we don't get a mouseup event. Default=1000
19401 * @property clickTimeThresh
19405 clickTimeThresh: 350,
19408 * Flag that indicates that either the drag pixel threshold or the
19409 * mousdown time threshold has been met
19410 * @property dragThreshMet
19415 dragThreshMet: false,
19418 * Timeout used for the click time threshold
19419 * @property clickTimeout
19424 clickTimeout: null,
19427 * The X position of the mousedown event stored for later use when a
19428 * drag threshold is met.
19437 * The Y position of the mousedown event stored for later use when a
19438 * drag threshold is met.
19447 * Each DragDrop instance must be registered with the DragDropMgr.
19448 * This is executed in DragDrop.init()
19449 * @method regDragDrop
19450 * @param {DragDrop} oDD the DragDrop object to register
19451 * @param {String} sGroup the name of the group this element belongs to
19454 regDragDrop: function(oDD, sGroup) {
19455 if (!this.initialized) { this.init(); }
19457 if (!this.ids[sGroup]) {
19458 this.ids[sGroup] = {};
19460 this.ids[sGroup][oDD.id] = oDD;
19464 * Removes the supplied dd instance from the supplied group. Executed
19465 * by DragDrop.removeFromGroup, so don't call this function directly.
19466 * @method removeDDFromGroup
19470 removeDDFromGroup: function(oDD, sGroup) {
19471 if (!this.ids[sGroup]) {
19472 this.ids[sGroup] = {};
19475 var obj = this.ids[sGroup];
19476 if (obj && obj[oDD.id]) {
19477 delete obj[oDD.id];
19482 * Unregisters a drag and drop item. This is executed in
19483 * DragDrop.unreg, use that method instead of calling this directly.
19488 _remove: function(oDD) {
19489 for (var g in oDD.groups) {
19490 if (g && this.ids[g][oDD.id]) {
19491 delete this.ids[g][oDD.id];
19494 delete this.handleIds[oDD.id];
19498 * Each DragDrop handle element must be registered. This is done
19499 * automatically when executing DragDrop.setHandleElId()
19500 * @method regHandle
19501 * @param {String} sDDId the DragDrop id this element is a handle for
19502 * @param {String} sHandleId the id of the element that is the drag
19506 regHandle: function(sDDId, sHandleId) {
19507 if (!this.handleIds[sDDId]) {
19508 this.handleIds[sDDId] = {};
19510 this.handleIds[sDDId][sHandleId] = sHandleId;
19514 * Utility function to determine if a given element has been
19515 * registered as a drag drop item.
19516 * @method isDragDrop
19517 * @param {String} id the element id to check
19518 * @return {boolean} true if this element is a DragDrop item,
19522 isDragDrop: function(id) {
19523 return ( this.getDDById(id) ) ? true : false;
19527 * Returns the drag and drop instances that are in all groups the
19528 * passed in instance belongs to.
19529 * @method getRelated
19530 * @param {DragDrop} p_oDD the obj to get related data for
19531 * @param {boolean} bTargetsOnly if true, only return targetable objs
19532 * @return {DragDrop[]} the related instances
19535 getRelated: function(p_oDD, bTargetsOnly) {
19537 for (var i in p_oDD.groups) {
19538 for (j in this.ids[i]) {
19539 var dd = this.ids[i][j];
19540 if (! this.isTypeOfDD(dd)) {
19543 if (!bTargetsOnly || dd.isTarget) {
19544 oDDs[oDDs.length] = dd;
19553 * Returns true if the specified dd target is a legal target for
19554 * the specifice drag obj
19555 * @method isLegalTarget
19556 * @param {DragDrop} the drag obj
19557 * @param {DragDrop} the target
19558 * @return {boolean} true if the target is a legal target for the
19562 isLegalTarget: function (oDD, oTargetDD) {
19563 var targets = this.getRelated(oDD, true);
19564 for (var i=0, len=targets.length;i<len;++i) {
19565 if (targets[i].id == oTargetDD.id) {
19574 * My goal is to be able to transparently determine if an object is
19575 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19576 * returns "object", oDD.constructor.toString() always returns
19577 * "DragDrop" and not the name of the subclass. So for now it just
19578 * evaluates a well-known variable in DragDrop.
19579 * @method isTypeOfDD
19580 * @param {Object} the object to evaluate
19581 * @return {boolean} true if typeof oDD = DragDrop
19584 isTypeOfDD: function (oDD) {
19585 return (oDD && oDD.__ygDragDrop);
19589 * Utility function to determine if a given element has been
19590 * registered as a drag drop handle for the given Drag Drop object.
19592 * @param {String} id the element id to check
19593 * @return {boolean} true if this element is a DragDrop handle, false
19597 isHandle: function(sDDId, sHandleId) {
19598 return ( this.handleIds[sDDId] &&
19599 this.handleIds[sDDId][sHandleId] );
19603 * Returns the DragDrop instance for a given id
19604 * @method getDDById
19605 * @param {String} id the id of the DragDrop object
19606 * @return {DragDrop} the drag drop object, null if it is not found
19609 getDDById: function(id) {
19610 for (var i in this.ids) {
19611 if (this.ids[i][id]) {
19612 return this.ids[i][id];
19619 * Fired after a registered DragDrop object gets the mousedown event.
19620 * Sets up the events required to track the object being dragged
19621 * @method handleMouseDown
19622 * @param {Event} e the event
19623 * @param oDD the DragDrop object being dragged
19627 handleMouseDown: function(e, oDD) {
19629 Roo.QuickTips.disable();
19631 this.currentTarget = e.getTarget();
19633 this.dragCurrent = oDD;
19635 var el = oDD.getEl();
19637 // track start position
19638 this.startX = e.getPageX();
19639 this.startY = e.getPageY();
19641 this.deltaX = this.startX - el.offsetLeft;
19642 this.deltaY = this.startY - el.offsetTop;
19644 this.dragThreshMet = false;
19646 this.clickTimeout = setTimeout(
19648 var DDM = Roo.dd.DDM;
19649 DDM.startDrag(DDM.startX, DDM.startY);
19651 this.clickTimeThresh );
19655 * Fired when either the drag pixel threshol or the mousedown hold
19656 * time threshold has been met.
19657 * @method startDrag
19658 * @param x {int} the X position of the original mousedown
19659 * @param y {int} the Y position of the original mousedown
19662 startDrag: function(x, y) {
19663 clearTimeout(this.clickTimeout);
19664 if (this.dragCurrent) {
19665 this.dragCurrent.b4StartDrag(x, y);
19666 this.dragCurrent.startDrag(x, y);
19668 this.dragThreshMet = true;
19672 * Internal function to handle the mouseup event. Will be invoked
19673 * from the context of the document.
19674 * @method handleMouseUp
19675 * @param {Event} e the event
19679 handleMouseUp: function(e) {
19682 Roo.QuickTips.enable();
19684 if (! this.dragCurrent) {
19688 clearTimeout(this.clickTimeout);
19690 if (this.dragThreshMet) {
19691 this.fireEvents(e, true);
19701 * Utility to stop event propagation and event default, if these
19702 * features are turned on.
19703 * @method stopEvent
19704 * @param {Event} e the event as returned by this.getEvent()
19707 stopEvent: function(e){
19708 if(this.stopPropagation) {
19709 e.stopPropagation();
19712 if (this.preventDefault) {
19713 e.preventDefault();
19718 * Internal function to clean up event handlers after the drag
19719 * operation is complete
19721 * @param {Event} e the event
19725 stopDrag: function(e) {
19726 // Fire the drag end event for the item that was dragged
19727 if (this.dragCurrent) {
19728 if (this.dragThreshMet) {
19729 this.dragCurrent.b4EndDrag(e);
19730 this.dragCurrent.endDrag(e);
19733 this.dragCurrent.onMouseUp(e);
19736 this.dragCurrent = null;
19737 this.dragOvers = {};
19741 * Internal function to handle the mousemove event. Will be invoked
19742 * from the context of the html element.
19744 * @TODO figure out what we can do about mouse events lost when the
19745 * user drags objects beyond the window boundary. Currently we can
19746 * detect this in internet explorer by verifying that the mouse is
19747 * down during the mousemove event. Firefox doesn't give us the
19748 * button state on the mousemove event.
19749 * @method handleMouseMove
19750 * @param {Event} e the event
19754 handleMouseMove: function(e) {
19755 if (! this.dragCurrent) {
19759 // var button = e.which || e.button;
19761 // check for IE mouseup outside of page boundary
19762 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19764 return this.handleMouseUp(e);
19767 if (!this.dragThreshMet) {
19768 var diffX = Math.abs(this.startX - e.getPageX());
19769 var diffY = Math.abs(this.startY - e.getPageY());
19770 if (diffX > this.clickPixelThresh ||
19771 diffY > this.clickPixelThresh) {
19772 this.startDrag(this.startX, this.startY);
19776 if (this.dragThreshMet) {
19777 this.dragCurrent.b4Drag(e);
19778 this.dragCurrent.onDrag(e);
19779 if(!this.dragCurrent.moveOnly){
19780 this.fireEvents(e, false);
19790 * Iterates over all of the DragDrop elements to find ones we are
19791 * hovering over or dropping on
19792 * @method fireEvents
19793 * @param {Event} e the event
19794 * @param {boolean} isDrop is this a drop op or a mouseover op?
19798 fireEvents: function(e, isDrop) {
19799 var dc = this.dragCurrent;
19801 // If the user did the mouse up outside of the window, we could
19802 // get here even though we have ended the drag.
19803 if (!dc || dc.isLocked()) {
19807 var pt = e.getPoint();
19809 // cache the previous dragOver array
19815 var enterEvts = [];
19817 // Check to see if the object(s) we were hovering over is no longer
19818 // being hovered over so we can fire the onDragOut event
19819 for (var i in this.dragOvers) {
19821 var ddo = this.dragOvers[i];
19823 if (! this.isTypeOfDD(ddo)) {
19827 if (! this.isOverTarget(pt, ddo, this.mode)) {
19828 outEvts.push( ddo );
19831 oldOvers[i] = true;
19832 delete this.dragOvers[i];
19835 for (var sGroup in dc.groups) {
19837 if ("string" != typeof sGroup) {
19841 for (i in this.ids[sGroup]) {
19842 var oDD = this.ids[sGroup][i];
19843 if (! this.isTypeOfDD(oDD)) {
19847 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19848 if (this.isOverTarget(pt, oDD, this.mode)) {
19849 // look for drop interactions
19851 dropEvts.push( oDD );
19852 // look for drag enter and drag over interactions
19855 // initial drag over: dragEnter fires
19856 if (!oldOvers[oDD.id]) {
19857 enterEvts.push( oDD );
19858 // subsequent drag overs: dragOver fires
19860 overEvts.push( oDD );
19863 this.dragOvers[oDD.id] = oDD;
19871 if (outEvts.length) {
19872 dc.b4DragOut(e, outEvts);
19873 dc.onDragOut(e, outEvts);
19876 if (enterEvts.length) {
19877 dc.onDragEnter(e, enterEvts);
19880 if (overEvts.length) {
19881 dc.b4DragOver(e, overEvts);
19882 dc.onDragOver(e, overEvts);
19885 if (dropEvts.length) {
19886 dc.b4DragDrop(e, dropEvts);
19887 dc.onDragDrop(e, dropEvts);
19891 // fire dragout events
19893 for (i=0, len=outEvts.length; i<len; ++i) {
19894 dc.b4DragOut(e, outEvts[i].id);
19895 dc.onDragOut(e, outEvts[i].id);
19898 // fire enter events
19899 for (i=0,len=enterEvts.length; i<len; ++i) {
19900 // dc.b4DragEnter(e, oDD.id);
19901 dc.onDragEnter(e, enterEvts[i].id);
19904 // fire over events
19905 for (i=0,len=overEvts.length; i<len; ++i) {
19906 dc.b4DragOver(e, overEvts[i].id);
19907 dc.onDragOver(e, overEvts[i].id);
19910 // fire drop events
19911 for (i=0, len=dropEvts.length; i<len; ++i) {
19912 dc.b4DragDrop(e, dropEvts[i].id);
19913 dc.onDragDrop(e, dropEvts[i].id);
19918 // notify about a drop that did not find a target
19919 if (isDrop && !dropEvts.length) {
19920 dc.onInvalidDrop(e);
19926 * Helper function for getting the best match from the list of drag
19927 * and drop objects returned by the drag and drop events when we are
19928 * in INTERSECT mode. It returns either the first object that the
19929 * cursor is over, or the object that has the greatest overlap with
19930 * the dragged element.
19931 * @method getBestMatch
19932 * @param {DragDrop[]} dds The array of drag and drop objects
19934 * @return {DragDrop} The best single match
19937 getBestMatch: function(dds) {
19939 // Return null if the input is not what we expect
19940 //if (!dds || !dds.length || dds.length == 0) {
19942 // If there is only one item, it wins
19943 //} else if (dds.length == 1) {
19945 var len = dds.length;
19950 // Loop through the targeted items
19951 for (var i=0; i<len; ++i) {
19953 // If the cursor is over the object, it wins. If the
19954 // cursor is over multiple matches, the first one we come
19956 if (dd.cursorIsOver) {
19959 // Otherwise the object with the most overlap wins
19962 winner.overlap.getArea() < dd.overlap.getArea()) {
19973 * Refreshes the cache of the top-left and bottom-right points of the
19974 * drag and drop objects in the specified group(s). This is in the
19975 * format that is stored in the drag and drop instance, so typical
19978 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19982 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19984 * @TODO this really should be an indexed array. Alternatively this
19985 * method could accept both.
19986 * @method refreshCache
19987 * @param {Object} groups an associative array of groups to refresh
19990 refreshCache: function(groups) {
19991 for (var sGroup in groups) {
19992 if ("string" != typeof sGroup) {
19995 for (var i in this.ids[sGroup]) {
19996 var oDD = this.ids[sGroup][i];
19998 if (this.isTypeOfDD(oDD)) {
19999 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20000 var loc = this.getLocation(oDD);
20002 this.locationCache[oDD.id] = loc;
20004 delete this.locationCache[oDD.id];
20005 // this will unregister the drag and drop object if
20006 // the element is not in a usable state
20015 * This checks to make sure an element exists and is in the DOM. The
20016 * main purpose is to handle cases where innerHTML is used to remove
20017 * drag and drop objects from the DOM. IE provides an 'unspecified
20018 * error' when trying to access the offsetParent of such an element
20020 * @param {HTMLElement} el the element to check
20021 * @return {boolean} true if the element looks usable
20024 verifyEl: function(el) {
20029 parent = el.offsetParent;
20032 parent = el.offsetParent;
20043 * Returns a Region object containing the drag and drop element's position
20044 * and size, including the padding configured for it
20045 * @method getLocation
20046 * @param {DragDrop} oDD the drag and drop object to get the
20048 * @return {Roo.lib.Region} a Region object representing the total area
20049 * the element occupies, including any padding
20050 * the instance is configured for.
20053 getLocation: function(oDD) {
20054 if (! this.isTypeOfDD(oDD)) {
20058 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20061 pos= Roo.lib.Dom.getXY(el);
20069 x2 = x1 + el.offsetWidth;
20071 y2 = y1 + el.offsetHeight;
20073 t = y1 - oDD.padding[0];
20074 r = x2 + oDD.padding[1];
20075 b = y2 + oDD.padding[2];
20076 l = x1 - oDD.padding[3];
20078 return new Roo.lib.Region( t, r, b, l );
20082 * Checks the cursor location to see if it over the target
20083 * @method isOverTarget
20084 * @param {Roo.lib.Point} pt The point to evaluate
20085 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20086 * @return {boolean} true if the mouse is over the target
20090 isOverTarget: function(pt, oTarget, intersect) {
20091 // use cache if available
20092 var loc = this.locationCache[oTarget.id];
20093 if (!loc || !this.useCache) {
20094 loc = this.getLocation(oTarget);
20095 this.locationCache[oTarget.id] = loc;
20103 oTarget.cursorIsOver = loc.contains( pt );
20105 // DragDrop is using this as a sanity check for the initial mousedown
20106 // in this case we are done. In POINT mode, if the drag obj has no
20107 // contraints, we are also done. Otherwise we need to evaluate the
20108 // location of the target as related to the actual location of the
20109 // dragged element.
20110 var dc = this.dragCurrent;
20111 if (!dc || !dc.getTargetCoord ||
20112 (!intersect && !dc.constrainX && !dc.constrainY)) {
20113 return oTarget.cursorIsOver;
20116 oTarget.overlap = null;
20118 // Get the current location of the drag element, this is the
20119 // location of the mouse event less the delta that represents
20120 // where the original mousedown happened on the element. We
20121 // need to consider constraints and ticks as well.
20122 var pos = dc.getTargetCoord(pt.x, pt.y);
20124 var el = dc.getDragEl();
20125 var curRegion = new Roo.lib.Region( pos.y,
20126 pos.x + el.offsetWidth,
20127 pos.y + el.offsetHeight,
20130 var overlap = curRegion.intersect(loc);
20133 oTarget.overlap = overlap;
20134 return (intersect) ? true : oTarget.cursorIsOver;
20141 * unload event handler
20142 * @method _onUnload
20146 _onUnload: function(e, me) {
20147 Roo.dd.DragDropMgr.unregAll();
20151 * Cleans up the drag and drop events and objects.
20156 unregAll: function() {
20158 if (this.dragCurrent) {
20160 this.dragCurrent = null;
20163 this._execOnAll("unreg", []);
20165 for (i in this.elementCache) {
20166 delete this.elementCache[i];
20169 this.elementCache = {};
20174 * A cache of DOM elements
20175 * @property elementCache
20182 * Get the wrapper for the DOM element specified
20183 * @method getElWrapper
20184 * @param {String} id the id of the element to get
20185 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20187 * @deprecated This wrapper isn't that useful
20190 getElWrapper: function(id) {
20191 var oWrapper = this.elementCache[id];
20192 if (!oWrapper || !oWrapper.el) {
20193 oWrapper = this.elementCache[id] =
20194 new this.ElementWrapper(Roo.getDom(id));
20200 * Returns the actual DOM element
20201 * @method getElement
20202 * @param {String} id the id of the elment to get
20203 * @return {Object} The element
20204 * @deprecated use Roo.getDom instead
20207 getElement: function(id) {
20208 return Roo.getDom(id);
20212 * Returns the style property for the DOM element (i.e.,
20213 * document.getElById(id).style)
20215 * @param {String} id the id of the elment to get
20216 * @return {Object} The style property of the element
20217 * @deprecated use Roo.getDom instead
20220 getCss: function(id) {
20221 var el = Roo.getDom(id);
20222 return (el) ? el.style : null;
20226 * Inner class for cached elements
20227 * @class DragDropMgr.ElementWrapper
20232 ElementWrapper: function(el) {
20237 this.el = el || null;
20242 this.id = this.el && el.id;
20244 * A reference to the style property
20247 this.css = this.el && el.style;
20251 * Returns the X position of an html element
20253 * @param el the element for which to get the position
20254 * @return {int} the X coordinate
20256 * @deprecated use Roo.lib.Dom.getX instead
20259 getPosX: function(el) {
20260 return Roo.lib.Dom.getX(el);
20264 * Returns the Y position of an html element
20266 * @param el the element for which to get the position
20267 * @return {int} the Y coordinate
20268 * @deprecated use Roo.lib.Dom.getY instead
20271 getPosY: function(el) {
20272 return Roo.lib.Dom.getY(el);
20276 * Swap two nodes. In IE, we use the native method, for others we
20277 * emulate the IE behavior
20279 * @param n1 the first node to swap
20280 * @param n2 the other node to swap
20283 swapNode: function(n1, n2) {
20287 var p = n2.parentNode;
20288 var s = n2.nextSibling;
20291 p.insertBefore(n1, n2);
20292 } else if (n2 == n1.nextSibling) {
20293 p.insertBefore(n2, n1);
20295 n1.parentNode.replaceChild(n2, n1);
20296 p.insertBefore(n1, s);
20302 * Returns the current scroll position
20303 * @method getScroll
20307 getScroll: function () {
20308 var t, l, dde=document.documentElement, db=document.body;
20309 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20311 l = dde.scrollLeft;
20318 return { top: t, left: l };
20322 * Returns the specified element style property
20324 * @param {HTMLElement} el the element
20325 * @param {string} styleProp the style property
20326 * @return {string} The value of the style property
20327 * @deprecated use Roo.lib.Dom.getStyle
20330 getStyle: function(el, styleProp) {
20331 return Roo.fly(el).getStyle(styleProp);
20335 * Gets the scrollTop
20336 * @method getScrollTop
20337 * @return {int} the document's scrollTop
20340 getScrollTop: function () { return this.getScroll().top; },
20343 * Gets the scrollLeft
20344 * @method getScrollLeft
20345 * @return {int} the document's scrollTop
20348 getScrollLeft: function () { return this.getScroll().left; },
20351 * Sets the x/y position of an element to the location of the
20354 * @param {HTMLElement} moveEl The element to move
20355 * @param {HTMLElement} targetEl The position reference element
20358 moveToEl: function (moveEl, targetEl) {
20359 var aCoord = Roo.lib.Dom.getXY(targetEl);
20360 Roo.lib.Dom.setXY(moveEl, aCoord);
20364 * Numeric array sort function
20365 * @method numericSort
20368 numericSort: function(a, b) { return (a - b); },
20372 * @property _timeoutCount
20379 * Trying to make the load order less important. Without this we get
20380 * an error if this file is loaded before the Event Utility.
20381 * @method _addListeners
20385 _addListeners: function() {
20386 var DDM = Roo.dd.DDM;
20387 if ( Roo.lib.Event && document ) {
20390 if (DDM._timeoutCount > 2000) {
20392 setTimeout(DDM._addListeners, 10);
20393 if (document && document.body) {
20394 DDM._timeoutCount += 1;
20401 * Recursively searches the immediate parent and all child nodes for
20402 * the handle element in order to determine wheter or not it was
20404 * @method handleWasClicked
20405 * @param node the html element to inspect
20408 handleWasClicked: function(node, id) {
20409 if (this.isHandle(id, node.id)) {
20412 // check to see if this is a text node child of the one we want
20413 var p = node.parentNode;
20416 if (this.isHandle(id, p.id)) {
20431 // shorter alias, save a few bytes
20432 Roo.dd.DDM = Roo.dd.DragDropMgr;
20433 Roo.dd.DDM._addListeners();
20437 * Ext JS Library 1.1.1
20438 * Copyright(c) 2006-2007, Ext JS, LLC.
20440 * Originally Released Under LGPL - original licence link has changed is not relivant.
20443 * <script type="text/javascript">
20448 * A DragDrop implementation where the linked element follows the
20449 * mouse cursor during a drag.
20450 * @extends Roo.dd.DragDrop
20452 * @param {String} id the id of the linked element
20453 * @param {String} sGroup the group of related DragDrop items
20454 * @param {object} config an object containing configurable attributes
20455 * Valid properties for DD:
20458 Roo.dd.DD = function(id, sGroup, config) {
20460 this.init(id, sGroup, config);
20464 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20467 * When set to true, the utility automatically tries to scroll the browser
20468 * window wehn a drag and drop element is dragged near the viewport boundary.
20469 * Defaults to true.
20476 * Sets the pointer offset to the distance between the linked element's top
20477 * left corner and the location the element was clicked
20478 * @method autoOffset
20479 * @param {int} iPageX the X coordinate of the click
20480 * @param {int} iPageY the Y coordinate of the click
20482 autoOffset: function(iPageX, iPageY) {
20483 var x = iPageX - this.startPageX;
20484 var y = iPageY - this.startPageY;
20485 this.setDelta(x, y);
20489 * Sets the pointer offset. You can call this directly to force the
20490 * offset to be in a particular location (e.g., pass in 0,0 to set it
20491 * to the center of the object)
20493 * @param {int} iDeltaX the distance from the left
20494 * @param {int} iDeltaY the distance from the top
20496 setDelta: function(iDeltaX, iDeltaY) {
20497 this.deltaX = iDeltaX;
20498 this.deltaY = iDeltaY;
20502 * Sets the drag element to the location of the mousedown or click event,
20503 * maintaining the cursor location relative to the location on the element
20504 * that was clicked. Override this if you want to place the element in a
20505 * location other than where the cursor is.
20506 * @method setDragElPos
20507 * @param {int} iPageX the X coordinate of the mousedown or drag event
20508 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20510 setDragElPos: function(iPageX, iPageY) {
20511 // the first time we do this, we are going to check to make sure
20512 // the element has css positioning
20514 var el = this.getDragEl();
20515 this.alignElWithMouse(el, iPageX, iPageY);
20519 * Sets the element to the location of the mousedown or click event,
20520 * maintaining the cursor location relative to the location on the element
20521 * that was clicked. Override this if you want to place the element in a
20522 * location other than where the cursor is.
20523 * @method alignElWithMouse
20524 * @param {HTMLElement} el the element to move
20525 * @param {int} iPageX the X coordinate of the mousedown or drag event
20526 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20528 alignElWithMouse: function(el, iPageX, iPageY) {
20529 var oCoord = this.getTargetCoord(iPageX, iPageY);
20530 var fly = el.dom ? el : Roo.fly(el);
20531 if (!this.deltaSetXY) {
20532 var aCoord = [oCoord.x, oCoord.y];
20534 var newLeft = fly.getLeft(true);
20535 var newTop = fly.getTop(true);
20536 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20538 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20541 this.cachePosition(oCoord.x, oCoord.y);
20542 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20547 * Saves the most recent position so that we can reset the constraints and
20548 * tick marks on-demand. We need to know this so that we can calculate the
20549 * number of pixels the element is offset from its original position.
20550 * @method cachePosition
20551 * @param iPageX the current x position (optional, this just makes it so we
20552 * don't have to look it up again)
20553 * @param iPageY the current y position (optional, this just makes it so we
20554 * don't have to look it up again)
20556 cachePosition: function(iPageX, iPageY) {
20558 this.lastPageX = iPageX;
20559 this.lastPageY = iPageY;
20561 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20562 this.lastPageX = aCoord[0];
20563 this.lastPageY = aCoord[1];
20568 * Auto-scroll the window if the dragged object has been moved beyond the
20569 * visible window boundary.
20570 * @method autoScroll
20571 * @param {int} x the drag element's x position
20572 * @param {int} y the drag element's y position
20573 * @param {int} h the height of the drag element
20574 * @param {int} w the width of the drag element
20577 autoScroll: function(x, y, h, w) {
20580 // The client height
20581 var clientH = Roo.lib.Dom.getViewWidth();
20583 // The client width
20584 var clientW = Roo.lib.Dom.getViewHeight();
20586 // The amt scrolled down
20587 var st = this.DDM.getScrollTop();
20589 // The amt scrolled right
20590 var sl = this.DDM.getScrollLeft();
20592 // Location of the bottom of the element
20595 // Location of the right of the element
20598 // The distance from the cursor to the bottom of the visible area,
20599 // adjusted so that we don't scroll if the cursor is beyond the
20600 // element drag constraints
20601 var toBot = (clientH + st - y - this.deltaY);
20603 // The distance from the cursor to the right of the visible area
20604 var toRight = (clientW + sl - x - this.deltaX);
20607 // How close to the edge the cursor must be before we scroll
20608 // var thresh = (document.all) ? 100 : 40;
20611 // How many pixels to scroll per autoscroll op. This helps to reduce
20612 // clunky scrolling. IE is more sensitive about this ... it needs this
20613 // value to be higher.
20614 var scrAmt = (document.all) ? 80 : 30;
20616 // Scroll down if we are near the bottom of the visible page and the
20617 // obj extends below the crease
20618 if ( bot > clientH && toBot < thresh ) {
20619 window.scrollTo(sl, st + scrAmt);
20622 // Scroll up if the window is scrolled down and the top of the object
20623 // goes above the top border
20624 if ( y < st && st > 0 && y - st < thresh ) {
20625 window.scrollTo(sl, st - scrAmt);
20628 // Scroll right if the obj is beyond the right border and the cursor is
20629 // near the border.
20630 if ( right > clientW && toRight < thresh ) {
20631 window.scrollTo(sl + scrAmt, st);
20634 // Scroll left if the window has been scrolled to the right and the obj
20635 // extends past the left border
20636 if ( x < sl && sl > 0 && x - sl < thresh ) {
20637 window.scrollTo(sl - scrAmt, st);
20643 * Finds the location the element should be placed if we want to move
20644 * it to where the mouse location less the click offset would place us.
20645 * @method getTargetCoord
20646 * @param {int} iPageX the X coordinate of the click
20647 * @param {int} iPageY the Y coordinate of the click
20648 * @return an object that contains the coordinates (Object.x and Object.y)
20651 getTargetCoord: function(iPageX, iPageY) {
20654 var x = iPageX - this.deltaX;
20655 var y = iPageY - this.deltaY;
20657 if (this.constrainX) {
20658 if (x < this.minX) { x = this.minX; }
20659 if (x > this.maxX) { x = this.maxX; }
20662 if (this.constrainY) {
20663 if (y < this.minY) { y = this.minY; }
20664 if (y > this.maxY) { y = this.maxY; }
20667 x = this.getTick(x, this.xTicks);
20668 y = this.getTick(y, this.yTicks);
20675 * Sets up config options specific to this class. Overrides
20676 * Roo.dd.DragDrop, but all versions of this method through the
20677 * inheritance chain are called
20679 applyConfig: function() {
20680 Roo.dd.DD.superclass.applyConfig.call(this);
20681 this.scroll = (this.config.scroll !== false);
20685 * Event that fires prior to the onMouseDown event. Overrides
20688 b4MouseDown: function(e) {
20689 // this.resetConstraints();
20690 this.autoOffset(e.getPageX(),
20695 * Event that fires prior to the onDrag event. Overrides
20698 b4Drag: function(e) {
20699 this.setDragElPos(e.getPageX(),
20703 toString: function() {
20704 return ("DD " + this.id);
20707 //////////////////////////////////////////////////////////////////////////
20708 // Debugging ygDragDrop events that can be overridden
20709 //////////////////////////////////////////////////////////////////////////
20711 startDrag: function(x, y) {
20714 onDrag: function(e) {
20717 onDragEnter: function(e, id) {
20720 onDragOver: function(e, id) {
20723 onDragOut: function(e, id) {
20726 onDragDrop: function(e, id) {
20729 endDrag: function(e) {
20736 * Ext JS Library 1.1.1
20737 * Copyright(c) 2006-2007, Ext JS, LLC.
20739 * Originally Released Under LGPL - original licence link has changed is not relivant.
20742 * <script type="text/javascript">
20746 * @class Roo.dd.DDProxy
20747 * A DragDrop implementation that inserts an empty, bordered div into
20748 * the document that follows the cursor during drag operations. At the time of
20749 * the click, the frame div is resized to the dimensions of the linked html
20750 * element, and moved to the exact location of the linked element.
20752 * References to the "frame" element refer to the single proxy element that
20753 * was created to be dragged in place of all DDProxy elements on the
20756 * @extends Roo.dd.DD
20758 * @param {String} id the id of the linked html element
20759 * @param {String} sGroup the group of related DragDrop objects
20760 * @param {object} config an object containing configurable attributes
20761 * Valid properties for DDProxy in addition to those in DragDrop:
20762 * resizeFrame, centerFrame, dragElId
20764 Roo.dd.DDProxy = function(id, sGroup, config) {
20766 this.init(id, sGroup, config);
20772 * The default drag frame div id
20773 * @property Roo.dd.DDProxy.dragElId
20777 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20779 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20782 * By default we resize the drag frame to be the same size as the element
20783 * we want to drag (this is to get the frame effect). We can turn it off
20784 * if we want a different behavior.
20785 * @property resizeFrame
20791 * By default the frame is positioned exactly where the drag element is, so
20792 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20793 * you do not have constraints on the obj is to have the drag frame centered
20794 * around the cursor. Set centerFrame to true for this effect.
20795 * @property centerFrame
20798 centerFrame: false,
20801 * Creates the proxy element if it does not yet exist
20802 * @method createFrame
20804 createFrame: function() {
20806 var body = document.body;
20808 if (!body || !body.firstChild) {
20809 setTimeout( function() { self.createFrame(); }, 50 );
20813 var div = this.getDragEl();
20816 div = document.createElement("div");
20817 div.id = this.dragElId;
20820 s.position = "absolute";
20821 s.visibility = "hidden";
20823 s.border = "2px solid #aaa";
20826 // appendChild can blow up IE if invoked prior to the window load event
20827 // while rendering a table. It is possible there are other scenarios
20828 // that would cause this to happen as well.
20829 body.insertBefore(div, body.firstChild);
20834 * Initialization for the drag frame element. Must be called in the
20835 * constructor of all subclasses
20836 * @method initFrame
20838 initFrame: function() {
20839 this.createFrame();
20842 applyConfig: function() {
20843 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20845 this.resizeFrame = (this.config.resizeFrame !== false);
20846 this.centerFrame = (this.config.centerFrame);
20847 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20851 * Resizes the drag frame to the dimensions of the clicked object, positions
20852 * it over the object, and finally displays it
20853 * @method showFrame
20854 * @param {int} iPageX X click position
20855 * @param {int} iPageY Y click position
20858 showFrame: function(iPageX, iPageY) {
20859 var el = this.getEl();
20860 var dragEl = this.getDragEl();
20861 var s = dragEl.style;
20863 this._resizeProxy();
20865 if (this.centerFrame) {
20866 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20867 Math.round(parseInt(s.height, 10)/2) );
20870 this.setDragElPos(iPageX, iPageY);
20872 Roo.fly(dragEl).show();
20876 * The proxy is automatically resized to the dimensions of the linked
20877 * element when a drag is initiated, unless resizeFrame is set to false
20878 * @method _resizeProxy
20881 _resizeProxy: function() {
20882 if (this.resizeFrame) {
20883 var el = this.getEl();
20884 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20888 // overrides Roo.dd.DragDrop
20889 b4MouseDown: function(e) {
20890 var x = e.getPageX();
20891 var y = e.getPageY();
20892 this.autoOffset(x, y);
20893 this.setDragElPos(x, y);
20896 // overrides Roo.dd.DragDrop
20897 b4StartDrag: function(x, y) {
20898 // show the drag frame
20899 this.showFrame(x, y);
20902 // overrides Roo.dd.DragDrop
20903 b4EndDrag: function(e) {
20904 Roo.fly(this.getDragEl()).hide();
20907 // overrides Roo.dd.DragDrop
20908 // By default we try to move the element to the last location of the frame.
20909 // This is so that the default behavior mirrors that of Roo.dd.DD.
20910 endDrag: function(e) {
20912 var lel = this.getEl();
20913 var del = this.getDragEl();
20915 // Show the drag frame briefly so we can get its position
20916 del.style.visibility = "";
20919 // Hide the linked element before the move to get around a Safari
20921 lel.style.visibility = "hidden";
20922 Roo.dd.DDM.moveToEl(lel, del);
20923 del.style.visibility = "hidden";
20924 lel.style.visibility = "";
20929 beforeMove : function(){
20933 afterDrag : function(){
20937 toString: function() {
20938 return ("DDProxy " + this.id);
20944 * Ext JS Library 1.1.1
20945 * Copyright(c) 2006-2007, Ext JS, LLC.
20947 * Originally Released Under LGPL - original licence link has changed is not relivant.
20950 * <script type="text/javascript">
20954 * @class Roo.dd.DDTarget
20955 * A DragDrop implementation that does not move, but can be a drop
20956 * target. You would get the same result by simply omitting implementation
20957 * for the event callbacks, but this way we reduce the processing cost of the
20958 * event listener and the callbacks.
20959 * @extends Roo.dd.DragDrop
20961 * @param {String} id the id of the element that is a drop target
20962 * @param {String} sGroup the group of related DragDrop objects
20963 * @param {object} config an object containing configurable attributes
20964 * Valid properties for DDTarget in addition to those in
20968 Roo.dd.DDTarget = function(id, sGroup, config) {
20970 this.initTarget(id, sGroup, config);
20972 if (config.listeners || config.events) {
20973 Roo.dd.DragDrop.superclass.constructor.call(this, {
20974 listeners : config.listeners || {},
20975 events : config.events || {}
20980 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20981 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20982 toString: function() {
20983 return ("DDTarget " + this.id);
20988 * Ext JS Library 1.1.1
20989 * Copyright(c) 2006-2007, Ext JS, LLC.
20991 * Originally Released Under LGPL - original licence link has changed is not relivant.
20994 * <script type="text/javascript">
20999 * @class Roo.dd.ScrollManager
21000 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21001 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21004 Roo.dd.ScrollManager = function(){
21005 var ddm = Roo.dd.DragDropMgr;
21012 var onStop = function(e){
21017 var triggerRefresh = function(){
21018 if(ddm.dragCurrent){
21019 ddm.refreshCache(ddm.dragCurrent.groups);
21023 var doScroll = function(){
21024 if(ddm.dragCurrent){
21025 var dds = Roo.dd.ScrollManager;
21027 if(proc.el.scroll(proc.dir, dds.increment)){
21031 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21036 var clearProc = function(){
21038 clearInterval(proc.id);
21045 var startProc = function(el, dir){
21046 Roo.log('scroll startproc');
21050 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21053 var onFire = function(e, isDrop){
21055 if(isDrop || !ddm.dragCurrent){ return; }
21056 var dds = Roo.dd.ScrollManager;
21057 if(!dragEl || dragEl != ddm.dragCurrent){
21058 dragEl = ddm.dragCurrent;
21059 // refresh regions on drag start
21060 dds.refreshCache();
21063 var xy = Roo.lib.Event.getXY(e);
21064 var pt = new Roo.lib.Point(xy[0], xy[1]);
21065 for(var id in els){
21066 var el = els[id], r = el._region;
21067 if(r && r.contains(pt) && el.isScrollable()){
21068 if(r.bottom - pt.y <= dds.thresh){
21070 startProc(el, "down");
21073 }else if(r.right - pt.x <= dds.thresh){
21075 startProc(el, "left");
21078 }else if(pt.y - r.top <= dds.thresh){
21080 startProc(el, "up");
21083 }else if(pt.x - r.left <= dds.thresh){
21085 startProc(el, "right");
21094 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21095 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21099 * Registers new overflow element(s) to auto scroll
21100 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21102 register : function(el){
21103 if(el instanceof Array){
21104 for(var i = 0, len = el.length; i < len; i++) {
21105 this.register(el[i]);
21111 Roo.dd.ScrollManager.els = els;
21115 * Unregisters overflow element(s) so they are no longer scrolled
21116 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21118 unregister : function(el){
21119 if(el instanceof Array){
21120 for(var i = 0, len = el.length; i < len; i++) {
21121 this.unregister(el[i]);
21130 * The number of pixels from the edge of a container the pointer needs to be to
21131 * trigger scrolling (defaults to 25)
21137 * The number of pixels to scroll in each scroll increment (defaults to 50)
21143 * The frequency of scrolls in milliseconds (defaults to 500)
21149 * True to animate the scroll (defaults to true)
21155 * The animation duration in seconds -
21156 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21162 * Manually trigger a cache refresh.
21164 refreshCache : function(){
21165 for(var id in els){
21166 if(typeof els[id] == 'object'){ // for people extending the object prototype
21167 els[id]._region = els[id].getRegion();
21174 * Ext JS Library 1.1.1
21175 * Copyright(c) 2006-2007, Ext JS, LLC.
21177 * Originally Released Under LGPL - original licence link has changed is not relivant.
21180 * <script type="text/javascript">
21185 * @class Roo.dd.Registry
21186 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21187 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21190 Roo.dd.Registry = function(){
21193 var autoIdSeed = 0;
21195 var getId = function(el, autogen){
21196 if(typeof el == "string"){
21200 if(!id && autogen !== false){
21201 id = "roodd-" + (++autoIdSeed);
21209 * Register a drag drop element
21210 * @param {String|HTMLElement} element The id or DOM node to register
21211 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21212 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21213 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21214 * populated in the data object (if applicable):
21216 Value Description<br />
21217 --------- ------------------------------------------<br />
21218 handles Array of DOM nodes that trigger dragging<br />
21219 for the element being registered<br />
21220 isHandle True if the element passed in triggers<br />
21221 dragging itself, else false
21224 register : function(el, data){
21226 if(typeof el == "string"){
21227 el = document.getElementById(el);
21230 elements[getId(el)] = data;
21231 if(data.isHandle !== false){
21232 handles[data.ddel.id] = data;
21235 var hs = data.handles;
21236 for(var i = 0, len = hs.length; i < len; i++){
21237 handles[getId(hs[i])] = data;
21243 * Unregister a drag drop element
21244 * @param {String|HTMLElement} element The id or DOM node to unregister
21246 unregister : function(el){
21247 var id = getId(el, false);
21248 var data = elements[id];
21250 delete elements[id];
21252 var hs = data.handles;
21253 for(var i = 0, len = hs.length; i < len; i++){
21254 delete handles[getId(hs[i], false)];
21261 * Returns the handle registered for a DOM Node by id
21262 * @param {String|HTMLElement} id The DOM node or id to look up
21263 * @return {Object} handle The custom handle data
21265 getHandle : function(id){
21266 if(typeof id != "string"){ // must be element?
21269 return handles[id];
21273 * Returns the handle that is registered for the DOM node that is the target of the event
21274 * @param {Event} e The event
21275 * @return {Object} handle The custom handle data
21277 getHandleFromEvent : function(e){
21278 var t = Roo.lib.Event.getTarget(e);
21279 return t ? handles[t.id] : null;
21283 * Returns a custom data object that is registered for a DOM node by id
21284 * @param {String|HTMLElement} id The DOM node or id to look up
21285 * @return {Object} data The custom data
21287 getTarget : function(id){
21288 if(typeof id != "string"){ // must be element?
21291 return elements[id];
21295 * Returns a custom data object that is registered for the DOM node that is the target of the event
21296 * @param {Event} e The event
21297 * @return {Object} data The custom data
21299 getTargetFromEvent : function(e){
21300 var t = Roo.lib.Event.getTarget(e);
21301 return t ? elements[t.id] || handles[t.id] : null;
21306 * Ext JS Library 1.1.1
21307 * Copyright(c) 2006-2007, Ext JS, LLC.
21309 * Originally Released Under LGPL - original licence link has changed is not relivant.
21312 * <script type="text/javascript">
21317 * @class Roo.dd.StatusProxy
21318 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21319 * default drag proxy used by all Roo.dd components.
21321 * @param {Object} config
21323 Roo.dd.StatusProxy = function(config){
21324 Roo.apply(this, config);
21325 this.id = this.id || Roo.id();
21326 this.el = new Roo.Layer({
21328 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21329 {tag: "div", cls: "x-dd-drop-icon"},
21330 {tag: "div", cls: "x-dd-drag-ghost"}
21333 shadow: !config || config.shadow !== false
21335 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21336 this.dropStatus = this.dropNotAllowed;
21339 Roo.dd.StatusProxy.prototype = {
21341 * @cfg {String} dropAllowed
21342 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21344 dropAllowed : "x-dd-drop-ok",
21346 * @cfg {String} dropNotAllowed
21347 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21349 dropNotAllowed : "x-dd-drop-nodrop",
21352 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21353 * over the current target element.
21354 * @param {String} cssClass The css class for the new drop status indicator image
21356 setStatus : function(cssClass){
21357 cssClass = cssClass || this.dropNotAllowed;
21358 if(this.dropStatus != cssClass){
21359 this.el.replaceClass(this.dropStatus, cssClass);
21360 this.dropStatus = cssClass;
21365 * Resets the status indicator to the default dropNotAllowed value
21366 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21368 reset : function(clearGhost){
21369 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21370 this.dropStatus = this.dropNotAllowed;
21372 this.ghost.update("");
21377 * Updates the contents of the ghost element
21378 * @param {String} html The html that will replace the current innerHTML of the ghost element
21380 update : function(html){
21381 if(typeof html == "string"){
21382 this.ghost.update(html);
21384 this.ghost.update("");
21385 html.style.margin = "0";
21386 this.ghost.dom.appendChild(html);
21388 // ensure float = none set?? cant remember why though.
21389 var el = this.ghost.dom.firstChild;
21391 Roo.fly(el).setStyle('float', 'none');
21396 * Returns the underlying proxy {@link Roo.Layer}
21397 * @return {Roo.Layer} el
21399 getEl : function(){
21404 * Returns the ghost element
21405 * @return {Roo.Element} el
21407 getGhost : function(){
21413 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21415 hide : function(clear){
21423 * Stops the repair animation if it's currently running
21426 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21432 * Displays this proxy
21439 * Force the Layer to sync its shadow and shim positions to the element
21446 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21447 * invalid drop operation by the item being dragged.
21448 * @param {Array} xy The XY position of the element ([x, y])
21449 * @param {Function} callback The function to call after the repair is complete
21450 * @param {Object} scope The scope in which to execute the callback
21452 repair : function(xy, callback, scope){
21453 this.callback = callback;
21454 this.scope = scope;
21455 if(xy && this.animRepair !== false){
21456 this.el.addClass("x-dd-drag-repair");
21457 this.el.hideUnders(true);
21458 this.anim = this.el.shift({
21459 duration: this.repairDuration || .5,
21463 callback: this.afterRepair,
21467 this.afterRepair();
21472 afterRepair : function(){
21474 if(typeof this.callback == "function"){
21475 this.callback.call(this.scope || this);
21477 this.callback = null;
21482 * Ext JS Library 1.1.1
21483 * Copyright(c) 2006-2007, Ext JS, LLC.
21485 * Originally Released Under LGPL - original licence link has changed is not relivant.
21488 * <script type="text/javascript">
21492 * @class Roo.dd.DragSource
21493 * @extends Roo.dd.DDProxy
21494 * A simple class that provides the basic implementation needed to make any element draggable.
21496 * @param {String/HTMLElement/Element} el The container element
21497 * @param {Object} config
21499 Roo.dd.DragSource = function(el, config){
21500 this.el = Roo.get(el);
21501 this.dragData = {};
21503 Roo.apply(this, config);
21506 this.proxy = new Roo.dd.StatusProxy();
21509 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21510 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21512 this.dragging = false;
21515 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21517 * @cfg {String} dropAllowed
21518 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21520 dropAllowed : "x-dd-drop-ok",
21522 * @cfg {String} dropNotAllowed
21523 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21525 dropNotAllowed : "x-dd-drop-nodrop",
21528 * Returns the data object associated with this drag source
21529 * @return {Object} data An object containing arbitrary data
21531 getDragData : function(e){
21532 return this.dragData;
21536 onDragEnter : function(e, id){
21537 var target = Roo.dd.DragDropMgr.getDDById(id);
21538 this.cachedTarget = target;
21539 if(this.beforeDragEnter(target, e, id) !== false){
21540 if(target.isNotifyTarget){
21541 var status = target.notifyEnter(this, e, this.dragData);
21542 this.proxy.setStatus(status);
21544 this.proxy.setStatus(this.dropAllowed);
21547 if(this.afterDragEnter){
21549 * An empty function by default, but provided so that you can perform a custom action
21550 * when the dragged item enters the drop target by providing an implementation.
21551 * @param {Roo.dd.DragDrop} target The drop target
21552 * @param {Event} e The event object
21553 * @param {String} id The id of the dragged element
21554 * @method afterDragEnter
21556 this.afterDragEnter(target, e, id);
21562 * An empty function by default, but provided so that you can perform a custom action
21563 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21564 * @param {Roo.dd.DragDrop} target The drop target
21565 * @param {Event} e The event object
21566 * @param {String} id The id of the dragged element
21567 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21569 beforeDragEnter : function(target, e, id){
21574 alignElWithMouse: function() {
21575 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21580 onDragOver : function(e, id){
21581 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21582 if(this.beforeDragOver(target, e, id) !== false){
21583 if(target.isNotifyTarget){
21584 var status = target.notifyOver(this, e, this.dragData);
21585 this.proxy.setStatus(status);
21588 if(this.afterDragOver){
21590 * An empty function by default, but provided so that you can perform a custom action
21591 * while the dragged item is over the drop target by providing an implementation.
21592 * @param {Roo.dd.DragDrop} target The drop target
21593 * @param {Event} e The event object
21594 * @param {String} id The id of the dragged element
21595 * @method afterDragOver
21597 this.afterDragOver(target, e, id);
21603 * An empty function by default, but provided so that you can perform a custom action
21604 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21605 * @param {Roo.dd.DragDrop} target The drop target
21606 * @param {Event} e The event object
21607 * @param {String} id The id of the dragged element
21608 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21610 beforeDragOver : function(target, e, id){
21615 onDragOut : function(e, id){
21616 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21617 if(this.beforeDragOut(target, e, id) !== false){
21618 if(target.isNotifyTarget){
21619 target.notifyOut(this, e, this.dragData);
21621 this.proxy.reset();
21622 if(this.afterDragOut){
21624 * An empty function by default, but provided so that you can perform a custom action
21625 * after the dragged item is dragged out of the target without dropping.
21626 * @param {Roo.dd.DragDrop} target The drop target
21627 * @param {Event} e The event object
21628 * @param {String} id The id of the dragged element
21629 * @method afterDragOut
21631 this.afterDragOut(target, e, id);
21634 this.cachedTarget = null;
21638 * An empty function by default, but provided so that you can perform a custom action before the dragged
21639 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21640 * @param {Roo.dd.DragDrop} target The drop target
21641 * @param {Event} e The event object
21642 * @param {String} id The id of the dragged element
21643 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21645 beforeDragOut : function(target, e, id){
21650 onDragDrop : function(e, id){
21651 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21652 if(this.beforeDragDrop(target, e, id) !== false){
21653 if(target.isNotifyTarget){
21654 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21655 this.onValidDrop(target, e, id);
21657 this.onInvalidDrop(target, e, id);
21660 this.onValidDrop(target, e, id);
21663 if(this.afterDragDrop){
21665 * An empty function by default, but provided so that you can perform a custom action
21666 * after a valid drag drop has occurred by providing an implementation.
21667 * @param {Roo.dd.DragDrop} target The drop target
21668 * @param {Event} e The event object
21669 * @param {String} id The id of the dropped element
21670 * @method afterDragDrop
21672 this.afterDragDrop(target, e, id);
21675 delete this.cachedTarget;
21679 * An empty function by default, but provided so that you can perform a custom action before the dragged
21680 * item is dropped onto the target and optionally cancel the onDragDrop.
21681 * @param {Roo.dd.DragDrop} target The drop target
21682 * @param {Event} e The event object
21683 * @param {String} id The id of the dragged element
21684 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21686 beforeDragDrop : function(target, e, id){
21691 onValidDrop : function(target, e, id){
21693 if(this.afterValidDrop){
21695 * An empty function by default, but provided so that you can perform a custom action
21696 * after a valid drop has occurred by providing an implementation.
21697 * @param {Object} target The target DD
21698 * @param {Event} e The event object
21699 * @param {String} id The id of the dropped element
21700 * @method afterInvalidDrop
21702 this.afterValidDrop(target, e, id);
21707 getRepairXY : function(e, data){
21708 return this.el.getXY();
21712 onInvalidDrop : function(target, e, id){
21713 this.beforeInvalidDrop(target, e, id);
21714 if(this.cachedTarget){
21715 if(this.cachedTarget.isNotifyTarget){
21716 this.cachedTarget.notifyOut(this, e, this.dragData);
21718 this.cacheTarget = null;
21720 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21722 if(this.afterInvalidDrop){
21724 * An empty function by default, but provided so that you can perform a custom action
21725 * after an invalid drop has occurred by providing an implementation.
21726 * @param {Event} e The event object
21727 * @param {String} id The id of the dropped element
21728 * @method afterInvalidDrop
21730 this.afterInvalidDrop(e, id);
21735 afterRepair : function(){
21737 this.el.highlight(this.hlColor || "c3daf9");
21739 this.dragging = false;
21743 * An empty function by default, but provided so that you can perform a custom action after an invalid
21744 * drop has occurred.
21745 * @param {Roo.dd.DragDrop} target The drop target
21746 * @param {Event} e The event object
21747 * @param {String} id The id of the dragged element
21748 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21750 beforeInvalidDrop : function(target, e, id){
21755 handleMouseDown : function(e){
21756 if(this.dragging) {
21759 var data = this.getDragData(e);
21760 if(data && this.onBeforeDrag(data, e) !== false){
21761 this.dragData = data;
21763 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21768 * An empty function by default, but provided so that you can perform a custom action before the initial
21769 * drag event begins and optionally cancel it.
21770 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21771 * @param {Event} e The event object
21772 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21774 onBeforeDrag : function(data, e){
21779 * An empty function by default, but provided so that you can perform a custom action once the initial
21780 * drag event has begun. The drag cannot be canceled from this function.
21781 * @param {Number} x The x position of the click on the dragged object
21782 * @param {Number} y The y position of the click on the dragged object
21784 onStartDrag : Roo.emptyFn,
21786 // private - YUI override
21787 startDrag : function(x, y){
21788 this.proxy.reset();
21789 this.dragging = true;
21790 this.proxy.update("");
21791 this.onInitDrag(x, y);
21796 onInitDrag : function(x, y){
21797 var clone = this.el.dom.cloneNode(true);
21798 clone.id = Roo.id(); // prevent duplicate ids
21799 this.proxy.update(clone);
21800 this.onStartDrag(x, y);
21805 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21806 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21808 getProxy : function(){
21813 * Hides the drag source's {@link Roo.dd.StatusProxy}
21815 hideProxy : function(){
21817 this.proxy.reset(true);
21818 this.dragging = false;
21822 triggerCacheRefresh : function(){
21823 Roo.dd.DDM.refreshCache(this.groups);
21826 // private - override to prevent hiding
21827 b4EndDrag: function(e) {
21830 // private - override to prevent moving
21831 endDrag : function(e){
21832 this.onEndDrag(this.dragData, e);
21836 onEndDrag : function(data, e){
21839 // private - pin to cursor
21840 autoOffset : function(x, y) {
21841 this.setDelta(-12, -20);
21845 * Ext JS Library 1.1.1
21846 * Copyright(c) 2006-2007, Ext JS, LLC.
21848 * Originally Released Under LGPL - original licence link has changed is not relivant.
21851 * <script type="text/javascript">
21856 * @class Roo.dd.DropTarget
21857 * @extends Roo.dd.DDTarget
21858 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21859 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21861 * @param {String/HTMLElement/Element} el The container element
21862 * @param {Object} config
21864 Roo.dd.DropTarget = function(el, config){
21865 this.el = Roo.get(el);
21867 var listeners = false; ;
21868 if (config && config.listeners) {
21869 listeners= config.listeners;
21870 delete config.listeners;
21872 Roo.apply(this, config);
21874 if(this.containerScroll){
21875 Roo.dd.ScrollManager.register(this.el);
21879 * @scope Roo.dd.DropTarget
21884 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21885 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21886 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21888 * IMPORTANT : it should set this.overClass and this.dropAllowed
21890 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21891 * @param {Event} e The event
21892 * @param {Object} data An object containing arbitrary data supplied by the drag source
21898 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21899 * This method will be called on every mouse movement while the drag source is over the drop target.
21900 * This default implementation simply returns the dropAllowed config value.
21902 * IMPORTANT : it should set this.dropAllowed
21904 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21905 * @param {Event} e The event
21906 * @param {Object} data An object containing arbitrary data supplied by the drag source
21912 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21913 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21914 * overClass (if any) from the drop element.
21916 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21917 * @param {Event} e The event
21918 * @param {Object} data An object containing arbitrary data supplied by the drag source
21924 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21925 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21926 * implementation that does something to process the drop event and returns true so that the drag source's
21927 * repair action does not run.
21929 * IMPORTANT : it should set this.success
21931 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21932 * @param {Event} e The event
21933 * @param {Object} data An object containing arbitrary data supplied by the drag source
21939 Roo.dd.DropTarget.superclass.constructor.call( this,
21941 this.ddGroup || this.group,
21944 listeners : listeners || {}
21952 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21954 * @cfg {String} overClass
21955 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21958 * @cfg {String} ddGroup
21959 * The drag drop group to handle drop events for
21963 * @cfg {String} dropAllowed
21964 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21966 dropAllowed : "x-dd-drop-ok",
21968 * @cfg {String} dropNotAllowed
21969 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21971 dropNotAllowed : "x-dd-drop-nodrop",
21973 * @cfg {boolean} success
21974 * set this after drop listener..
21978 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21979 * if the drop point is valid for over/enter..
21986 isNotifyTarget : true,
21991 notifyEnter : function(dd, e, data)
21994 this.fireEvent('enter', dd, e, data);
21995 if(this.overClass){
21996 this.el.addClass(this.overClass);
21998 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21999 this.valid ? this.dropAllowed : this.dropNotAllowed
22006 notifyOver : function(dd, e, data)
22009 this.fireEvent('over', dd, e, data);
22010 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22011 this.valid ? this.dropAllowed : this.dropNotAllowed
22018 notifyOut : function(dd, e, data)
22020 this.fireEvent('out', dd, e, data);
22021 if(this.overClass){
22022 this.el.removeClass(this.overClass);
22029 notifyDrop : function(dd, e, data)
22031 this.success = false;
22032 this.fireEvent('drop', dd, e, data);
22033 return this.success;
22037 * Ext JS Library 1.1.1
22038 * Copyright(c) 2006-2007, Ext JS, LLC.
22040 * Originally Released Under LGPL - original licence link has changed is not relivant.
22043 * <script type="text/javascript">
22048 * @class Roo.dd.DragZone
22049 * @extends Roo.dd.DragSource
22050 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22051 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22053 * @param {String/HTMLElement/Element} el The container element
22054 * @param {Object} config
22056 Roo.dd.DragZone = function(el, config){
22057 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22058 if(this.containerScroll){
22059 Roo.dd.ScrollManager.register(this.el);
22063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22065 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22066 * for auto scrolling during drag operations.
22069 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22070 * method after a failed drop (defaults to "c3daf9" - light blue)
22074 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22075 * for a valid target to drag based on the mouse down. Override this method
22076 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22077 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22078 * @param {EventObject} e The mouse down event
22079 * @return {Object} The dragData
22081 getDragData : function(e){
22082 return Roo.dd.Registry.getHandleFromEvent(e);
22086 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22087 * this.dragData.ddel
22088 * @param {Number} x The x position of the click on the dragged object
22089 * @param {Number} y The y position of the click on the dragged object
22090 * @return {Boolean} true to continue the drag, false to cancel
22092 onInitDrag : function(x, y){
22093 this.proxy.update(this.dragData.ddel.cloneNode(true));
22094 this.onStartDrag(x, y);
22099 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22101 afterRepair : function(){
22103 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22105 this.dragging = false;
22109 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22110 * the XY of this.dragData.ddel
22111 * @param {EventObject} e The mouse up event
22112 * @return {Array} The xy location (e.g. [100, 200])
22114 getRepairXY : function(e){
22115 return Roo.Element.fly(this.dragData.ddel).getXY();
22119 * Ext JS Library 1.1.1
22120 * Copyright(c) 2006-2007, Ext JS, LLC.
22122 * Originally Released Under LGPL - original licence link has changed is not relivant.
22125 * <script type="text/javascript">
22128 * @class Roo.dd.DropZone
22129 * @extends Roo.dd.DropTarget
22130 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22131 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22133 * @param {String/HTMLElement/Element} el The container element
22134 * @param {Object} config
22136 Roo.dd.DropZone = function(el, config){
22137 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22142 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22143 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22144 * provide your own custom lookup.
22145 * @param {Event} e The event
22146 * @return {Object} data The custom data
22148 getTargetFromEvent : function(e){
22149 return Roo.dd.Registry.getTargetFromEvent(e);
22153 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22154 * that it has registered. This method has no default implementation and should be overridden to provide
22155 * node-specific processing if necessary.
22156 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22157 * {@link #getTargetFromEvent} for this node)
22158 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22159 * @param {Event} e The event
22160 * @param {Object} data An object containing arbitrary data supplied by the drag source
22162 onNodeEnter : function(n, dd, e, data){
22167 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22168 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22169 * overridden to provide the proper feedback.
22170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22171 * {@link #getTargetFromEvent} for this node)
22172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22173 * @param {Event} e The event
22174 * @param {Object} data An object containing arbitrary data supplied by the drag source
22175 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22176 * underlying {@link Roo.dd.StatusProxy} can be updated
22178 onNodeOver : function(n, dd, e, data){
22179 return this.dropAllowed;
22183 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22184 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22185 * node-specific processing if necessary.
22186 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22187 * {@link #getTargetFromEvent} for this node)
22188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22189 * @param {Event} e The event
22190 * @param {Object} data An object containing arbitrary data supplied by the drag source
22192 onNodeOut : function(n, dd, e, data){
22197 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22198 * the drop node. The default implementation returns false, so it should be overridden to provide the
22199 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22200 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22201 * {@link #getTargetFromEvent} for this node)
22202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22203 * @param {Event} e The event
22204 * @param {Object} data An object containing arbitrary data supplied by the drag source
22205 * @return {Boolean} True if the drop was valid, else false
22207 onNodeDrop : function(n, dd, e, data){
22212 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22213 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22214 * it should be overridden to provide the proper feedback if necessary.
22215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22216 * @param {Event} e The event
22217 * @param {Object} data An object containing arbitrary data supplied by the drag source
22218 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22219 * underlying {@link Roo.dd.StatusProxy} can be updated
22221 onContainerOver : function(dd, e, data){
22222 return this.dropNotAllowed;
22226 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22227 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22228 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22229 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22231 * @param {Event} e The event
22232 * @param {Object} data An object containing arbitrary data supplied by the drag source
22233 * @return {Boolean} True if the drop was valid, else false
22235 onContainerDrop : function(dd, e, data){
22240 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22241 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22242 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22243 * you should override this method and provide a custom implementation.
22244 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22245 * @param {Event} e The event
22246 * @param {Object} data An object containing arbitrary data supplied by the drag source
22247 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22248 * underlying {@link Roo.dd.StatusProxy} can be updated
22250 notifyEnter : function(dd, e, data){
22251 return this.dropNotAllowed;
22255 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22256 * This method will be called on every mouse movement while the drag source is over the drop zone.
22257 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22258 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22259 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22260 * registered node, it will call {@link #onContainerOver}.
22261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22262 * @param {Event} e The event
22263 * @param {Object} data An object containing arbitrary data supplied by the drag source
22264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22265 * underlying {@link Roo.dd.StatusProxy} can be updated
22267 notifyOver : function(dd, e, data){
22268 var n = this.getTargetFromEvent(e);
22269 if(!n){ // not over valid drop target
22270 if(this.lastOverNode){
22271 this.onNodeOut(this.lastOverNode, dd, e, data);
22272 this.lastOverNode = null;
22274 return this.onContainerOver(dd, e, data);
22276 if(this.lastOverNode != n){
22277 if(this.lastOverNode){
22278 this.onNodeOut(this.lastOverNode, dd, e, data);
22280 this.onNodeEnter(n, dd, e, data);
22281 this.lastOverNode = n;
22283 return this.onNodeOver(n, dd, e, data);
22287 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22288 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22289 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22291 * @param {Event} e The event
22292 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22294 notifyOut : function(dd, e, data){
22295 if(this.lastOverNode){
22296 this.onNodeOut(this.lastOverNode, dd, e, data);
22297 this.lastOverNode = null;
22302 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22303 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22304 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22305 * otherwise it will call {@link #onContainerDrop}.
22306 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22307 * @param {Event} e The event
22308 * @param {Object} data An object containing arbitrary data supplied by the drag source
22309 * @return {Boolean} True if the drop was valid, else false
22311 notifyDrop : function(dd, e, data){
22312 if(this.lastOverNode){
22313 this.onNodeOut(this.lastOverNode, dd, e, data);
22314 this.lastOverNode = null;
22316 var n = this.getTargetFromEvent(e);
22318 this.onNodeDrop(n, dd, e, data) :
22319 this.onContainerDrop(dd, e, data);
22323 triggerCacheRefresh : function(){
22324 Roo.dd.DDM.refreshCache(this.groups);
22328 * Ext JS Library 1.1.1
22329 * Copyright(c) 2006-2007, Ext JS, LLC.
22331 * Originally Released Under LGPL - original licence link has changed is not relivant.
22334 * <script type="text/javascript">
22339 * @class Roo.data.SortTypes
22341 * Defines the default sorting (casting?) comparison functions used when sorting data.
22343 Roo.data.SortTypes = {
22345 * Default sort that does nothing
22346 * @param {Mixed} s The value being converted
22347 * @return {Mixed} The comparison value
22349 none : function(s){
22354 * The regular expression used to strip tags
22358 stripTagsRE : /<\/?[^>]+>/gi,
22361 * Strips all HTML tags to sort on text only
22362 * @param {Mixed} s The value being converted
22363 * @return {String} The comparison value
22365 asText : function(s){
22366 return String(s).replace(this.stripTagsRE, "");
22370 * Strips all HTML tags to sort on text only - Case insensitive
22371 * @param {Mixed} s The value being converted
22372 * @return {String} The comparison value
22374 asUCText : function(s){
22375 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22379 * Case insensitive string
22380 * @param {Mixed} s The value being converted
22381 * @return {String} The comparison value
22383 asUCString : function(s) {
22384 return String(s).toUpperCase();
22389 * @param {Mixed} s The value being converted
22390 * @return {Number} The comparison value
22392 asDate : function(s) {
22396 if(s instanceof Date){
22397 return s.getTime();
22399 return Date.parse(String(s));
22404 * @param {Mixed} s The value being converted
22405 * @return {Float} The comparison value
22407 asFloat : function(s) {
22408 var val = parseFloat(String(s).replace(/,/g, ""));
22417 * @param {Mixed} s The value being converted
22418 * @return {Number} The comparison value
22420 asInt : function(s) {
22421 var val = parseInt(String(s).replace(/,/g, ""));
22429 * Ext JS Library 1.1.1
22430 * Copyright(c) 2006-2007, Ext JS, LLC.
22432 * Originally Released Under LGPL - original licence link has changed is not relivant.
22435 * <script type="text/javascript">
22439 * @class Roo.data.Record
22440 * Instances of this class encapsulate both record <em>definition</em> information, and record
22441 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22442 * to access Records cached in an {@link Roo.data.Store} object.<br>
22444 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22445 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22448 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22450 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22451 * {@link #create}. The parameters are the same.
22452 * @param {Array} data An associative Array of data values keyed by the field name.
22453 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22454 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22455 * not specified an integer id is generated.
22457 Roo.data.Record = function(data, id){
22458 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22463 * Generate a constructor for a specific record layout.
22464 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22465 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22466 * Each field definition object may contain the following properties: <ul>
22467 * <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,
22468 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22469 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22470 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22471 * is being used, then this is a string containing the javascript expression to reference the data relative to
22472 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22473 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22474 * this may be omitted.</p></li>
22475 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22476 * <ul><li>auto (Default, implies no conversion)</li>
22481 * <li>date</li></ul></p></li>
22482 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22483 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22484 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22485 * by the Reader into an object that will be stored in the Record. It is passed the
22486 * following parameters:<ul>
22487 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22489 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22491 * <br>usage:<br><pre><code>
22492 var TopicRecord = Roo.data.Record.create(
22493 {name: 'title', mapping: 'topic_title'},
22494 {name: 'author', mapping: 'username'},
22495 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22496 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22497 {name: 'lastPoster', mapping: 'user2'},
22498 {name: 'excerpt', mapping: 'post_text'}
22501 var myNewRecord = new TopicRecord({
22502 title: 'Do my job please',
22505 lastPost: new Date(),
22506 lastPoster: 'Animal',
22507 excerpt: 'No way dude!'
22509 myStore.add(myNewRecord);
22514 Roo.data.Record.create = function(o){
22515 var f = function(){
22516 f.superclass.constructor.apply(this, arguments);
22518 Roo.extend(f, Roo.data.Record);
22519 var p = f.prototype;
22520 p.fields = new Roo.util.MixedCollection(false, function(field){
22523 for(var i = 0, len = o.length; i < len; i++){
22524 p.fields.add(new Roo.data.Field(o[i]));
22526 f.getField = function(name){
22527 return p.fields.get(name);
22532 Roo.data.Record.AUTO_ID = 1000;
22533 Roo.data.Record.EDIT = 'edit';
22534 Roo.data.Record.REJECT = 'reject';
22535 Roo.data.Record.COMMIT = 'commit';
22537 Roo.data.Record.prototype = {
22539 * Readonly flag - true if this record has been modified.
22548 join : function(store){
22549 this.store = store;
22553 * Set the named field to the specified value.
22554 * @param {String} name The name of the field to set.
22555 * @param {Object} value The value to set the field to.
22557 set : function(name, value){
22558 if(this.data[name] == value){
22562 if(!this.modified){
22563 this.modified = {};
22565 if(typeof this.modified[name] == 'undefined'){
22566 this.modified[name] = this.data[name];
22568 this.data[name] = value;
22569 if(!this.editing && this.store){
22570 this.store.afterEdit(this);
22575 * Get the value of the named field.
22576 * @param {String} name The name of the field to get the value of.
22577 * @return {Object} The value of the field.
22579 get : function(name){
22580 return this.data[name];
22584 beginEdit : function(){
22585 this.editing = true;
22586 this.modified = {};
22590 cancelEdit : function(){
22591 this.editing = false;
22592 delete this.modified;
22596 endEdit : function(){
22597 this.editing = false;
22598 if(this.dirty && this.store){
22599 this.store.afterEdit(this);
22604 * Usually called by the {@link Roo.data.Store} which owns the Record.
22605 * Rejects all changes made to the Record since either creation, or the last commit operation.
22606 * Modified fields are reverted to their original values.
22608 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22609 * of reject operations.
22611 reject : function(){
22612 var m = this.modified;
22614 if(typeof m[n] != "function"){
22615 this.data[n] = m[n];
22618 this.dirty = false;
22619 delete this.modified;
22620 this.editing = false;
22622 this.store.afterReject(this);
22627 * Usually called by the {@link Roo.data.Store} which owns the Record.
22628 * Commits all changes made to the Record since either creation, or the last commit operation.
22630 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22631 * of commit operations.
22633 commit : function(){
22634 this.dirty = false;
22635 delete this.modified;
22636 this.editing = false;
22638 this.store.afterCommit(this);
22643 hasError : function(){
22644 return this.error != null;
22648 clearError : function(){
22653 * Creates a copy of this record.
22654 * @param {String} id (optional) A new record id if you don't want to use this record's id
22657 copy : function(newId) {
22658 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22662 * Ext JS Library 1.1.1
22663 * Copyright(c) 2006-2007, Ext JS, LLC.
22665 * Originally Released Under LGPL - original licence link has changed is not relivant.
22668 * <script type="text/javascript">
22674 * @class Roo.data.Store
22675 * @extends Roo.util.Observable
22676 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22677 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22679 * 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
22680 * has no knowledge of the format of the data returned by the Proxy.<br>
22682 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22683 * instances from the data object. These records are cached and made available through accessor functions.
22685 * Creates a new Store.
22686 * @param {Object} config A config object containing the objects needed for the Store to access data,
22687 * and read the data into Records.
22689 Roo.data.Store = function(config){
22690 this.data = new Roo.util.MixedCollection(false);
22691 this.data.getKey = function(o){
22694 this.baseParams = {};
22696 this.paramNames = {
22701 "multisort" : "_multisort"
22704 if(config && config.data){
22705 this.inlineData = config.data;
22706 delete config.data;
22709 Roo.apply(this, config);
22711 if(this.reader){ // reader passed
22712 this.reader = Roo.factory(this.reader, Roo.data);
22713 this.reader.xmodule = this.xmodule || false;
22714 if(!this.recordType){
22715 this.recordType = this.reader.recordType;
22717 if(this.reader.onMetaChange){
22718 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22722 if(this.recordType){
22723 this.fields = this.recordType.prototype.fields;
22725 this.modified = [];
22729 * @event datachanged
22730 * Fires when the data cache has changed, and a widget which is using this Store
22731 * as a Record cache should refresh its view.
22732 * @param {Store} this
22734 datachanged : true,
22736 * @event metachange
22737 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22738 * @param {Store} this
22739 * @param {Object} meta The JSON metadata
22744 * Fires when Records have been added to the Store
22745 * @param {Store} this
22746 * @param {Roo.data.Record[]} records The array of Records added
22747 * @param {Number} index The index at which the record(s) were added
22752 * Fires when a Record has been removed from the Store
22753 * @param {Store} this
22754 * @param {Roo.data.Record} record The Record that was removed
22755 * @param {Number} index The index at which the record was removed
22760 * Fires when a Record has been updated
22761 * @param {Store} this
22762 * @param {Roo.data.Record} record The Record that was updated
22763 * @param {String} operation The update operation being performed. Value may be one of:
22765 Roo.data.Record.EDIT
22766 Roo.data.Record.REJECT
22767 Roo.data.Record.COMMIT
22773 * Fires when the data cache has been cleared.
22774 * @param {Store} this
22778 * @event beforeload
22779 * Fires before a request is made for a new data object. If the beforeload handler returns false
22780 * the load action will be canceled.
22781 * @param {Store} this
22782 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22786 * @event beforeloadadd
22787 * Fires after a new set of Records has been loaded.
22788 * @param {Store} this
22789 * @param {Roo.data.Record[]} records The Records that were loaded
22790 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22792 beforeloadadd : true,
22795 * Fires after a new set of Records has been loaded, before they are added to the store.
22796 * @param {Store} this
22797 * @param {Roo.data.Record[]} records The Records that were loaded
22798 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22799 * @params {Object} return from reader
22803 * @event loadexception
22804 * Fires if an exception occurs in the Proxy during loading.
22805 * Called with the signature of the Proxy's "loadexception" event.
22806 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22809 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22810 * @param {Object} load options
22811 * @param {Object} jsonData from your request (normally this contains the Exception)
22813 loadexception : true
22817 this.proxy = Roo.factory(this.proxy, Roo.data);
22818 this.proxy.xmodule = this.xmodule || false;
22819 this.relayEvents(this.proxy, ["loadexception"]);
22821 this.sortToggle = {};
22822 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22824 Roo.data.Store.superclass.constructor.call(this);
22826 if(this.inlineData){
22827 this.loadData(this.inlineData);
22828 delete this.inlineData;
22832 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22834 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22835 * without a remote query - used by combo/forms at present.
22839 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22842 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22845 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22846 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22849 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22850 * on any HTTP request
22853 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22856 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22860 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22861 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22863 remoteSort : false,
22866 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22867 * loaded or when a record is removed. (defaults to false).
22869 pruneModifiedRecords : false,
22872 lastOptions : null,
22875 * Add Records to the Store and fires the add event.
22876 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22878 add : function(records){
22879 records = [].concat(records);
22880 for(var i = 0, len = records.length; i < len; i++){
22881 records[i].join(this);
22883 var index = this.data.length;
22884 this.data.addAll(records);
22885 this.fireEvent("add", this, records, index);
22889 * Remove a Record from the Store and fires the remove event.
22890 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22892 remove : function(record){
22893 var index = this.data.indexOf(record);
22894 this.data.removeAt(index);
22895 if(this.pruneModifiedRecords){
22896 this.modified.remove(record);
22898 this.fireEvent("remove", this, record, index);
22902 * Remove all Records from the Store and fires the clear event.
22904 removeAll : function(){
22906 if(this.pruneModifiedRecords){
22907 this.modified = [];
22909 this.fireEvent("clear", this);
22913 * Inserts Records to the Store at the given index and fires the add event.
22914 * @param {Number} index The start index at which to insert the passed Records.
22915 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22917 insert : function(index, records){
22918 records = [].concat(records);
22919 for(var i = 0, len = records.length; i < len; i++){
22920 this.data.insert(index, records[i]);
22921 records[i].join(this);
22923 this.fireEvent("add", this, records, index);
22927 * Get the index within the cache of the passed Record.
22928 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22929 * @return {Number} The index of the passed Record. Returns -1 if not found.
22931 indexOf : function(record){
22932 return this.data.indexOf(record);
22936 * Get the index within the cache of the Record with the passed id.
22937 * @param {String} id The id of the Record to find.
22938 * @return {Number} The index of the Record. Returns -1 if not found.
22940 indexOfId : function(id){
22941 return this.data.indexOfKey(id);
22945 * Get the Record with the specified id.
22946 * @param {String} id The id of the Record to find.
22947 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22949 getById : function(id){
22950 return this.data.key(id);
22954 * Get the Record at the specified index.
22955 * @param {Number} index The index of the Record to find.
22956 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22958 getAt : function(index){
22959 return this.data.itemAt(index);
22963 * Returns a range of Records between specified indices.
22964 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22965 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22966 * @return {Roo.data.Record[]} An array of Records
22968 getRange : function(start, end){
22969 return this.data.getRange(start, end);
22973 storeOptions : function(o){
22974 o = Roo.apply({}, o);
22977 this.lastOptions = o;
22981 * Loads the Record cache from the configured Proxy using the configured Reader.
22983 * If using remote paging, then the first load call must specify the <em>start</em>
22984 * and <em>limit</em> properties in the options.params property to establish the initial
22985 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22987 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22988 * and this call will return before the new data has been loaded. Perform any post-processing
22989 * in a callback function, or in a "load" event handler.</strong>
22991 * @param {Object} options An object containing properties which control loading options:<ul>
22992 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22993 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22994 * passed the following arguments:<ul>
22995 * <li>r : Roo.data.Record[]</li>
22996 * <li>options: Options object from the load call</li>
22997 * <li>success: Boolean success indicator</li></ul></li>
22998 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
22999 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23002 load : function(options){
23003 options = options || {};
23004 if(this.fireEvent("beforeload", this, options) !== false){
23005 this.storeOptions(options);
23006 var p = Roo.apply(options.params || {}, this.baseParams);
23007 // if meta was not loaded from remote source.. try requesting it.
23008 if (!this.reader.metaFromRemote) {
23009 p._requestMeta = 1;
23011 if(this.sortInfo && this.remoteSort){
23012 var pn = this.paramNames;
23013 p[pn["sort"]] = this.sortInfo.field;
23014 p[pn["dir"]] = this.sortInfo.direction;
23016 if (this.multiSort) {
23017 var pn = this.paramNames;
23018 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23021 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23026 * Reloads the Record cache from the configured Proxy using the configured Reader and
23027 * the options from the last load operation performed.
23028 * @param {Object} options (optional) An object containing properties which may override the options
23029 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23030 * the most recently used options are reused).
23032 reload : function(options){
23033 this.load(Roo.applyIf(options||{}, this.lastOptions));
23037 // Called as a callback by the Reader during a load operation.
23038 loadRecords : function(o, options, success){
23039 if(!o || success === false){
23040 if(success !== false){
23041 this.fireEvent("load", this, [], options, o);
23043 if(options.callback){
23044 options.callback.call(options.scope || this, [], options, false);
23048 // if data returned failure - throw an exception.
23049 if (o.success === false) {
23050 // show a message if no listener is registered.
23051 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23052 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23054 // loadmask wil be hooked into this..
23055 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23058 var r = o.records, t = o.totalRecords || r.length;
23060 this.fireEvent("beforeloadadd", this, r, options, o);
23062 if(!options || options.add !== true){
23063 if(this.pruneModifiedRecords){
23064 this.modified = [];
23066 for(var i = 0, len = r.length; i < len; i++){
23070 this.data = this.snapshot;
23071 delete this.snapshot;
23074 this.data.addAll(r);
23075 this.totalLength = t;
23077 this.fireEvent("datachanged", this);
23079 this.totalLength = Math.max(t, this.data.length+r.length);
23083 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23085 var e = new Roo.data.Record({});
23087 e.set(this.parent.displayField, this.parent.emptyTitle);
23088 e.set(this.parent.valueField, '');
23093 this.fireEvent("load", this, r, options, o);
23094 if(options.callback){
23095 options.callback.call(options.scope || this, r, options, true);
23101 * Loads data from a passed data block. A Reader which understands the format of the data
23102 * must have been configured in the constructor.
23103 * @param {Object} data The data block from which to read the Records. The format of the data expected
23104 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23105 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23107 loadData : function(o, append){
23108 var r = this.reader.readRecords(o);
23109 this.loadRecords(r, {add: append}, true);
23113 * Gets the number of cached records.
23115 * <em>If using paging, this may not be the total size of the dataset. If the data object
23116 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23117 * the data set size</em>
23119 getCount : function(){
23120 return this.data.length || 0;
23124 * Gets the total number of records in the dataset as returned by the server.
23126 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23127 * the dataset size</em>
23129 getTotalCount : function(){
23130 return this.totalLength || 0;
23134 * Returns the sort state of the Store as an object with two properties:
23136 field {String} The name of the field by which the Records are sorted
23137 direction {String} The sort order, "ASC" or "DESC"
23140 getSortState : function(){
23141 return this.sortInfo;
23145 applySort : function(){
23146 if(this.sortInfo && !this.remoteSort){
23147 var s = this.sortInfo, f = s.field;
23148 var st = this.fields.get(f).sortType;
23149 var fn = function(r1, r2){
23150 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23151 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23153 this.data.sort(s.direction, fn);
23154 if(this.snapshot && this.snapshot != this.data){
23155 this.snapshot.sort(s.direction, fn);
23161 * Sets the default sort column and order to be used by the next load operation.
23162 * @param {String} fieldName The name of the field to sort by.
23163 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23165 setDefaultSort : function(field, dir){
23166 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23170 * Sort the Records.
23171 * If remote sorting is used, the sort is performed on the server, and the cache is
23172 * reloaded. If local sorting is used, the cache is sorted internally.
23173 * @param {String} fieldName The name of the field to sort by.
23174 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23176 sort : function(fieldName, dir){
23177 var f = this.fields.get(fieldName);
23179 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23181 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23182 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23187 this.sortToggle[f.name] = dir;
23188 this.sortInfo = {field: f.name, direction: dir};
23189 if(!this.remoteSort){
23191 this.fireEvent("datachanged", this);
23193 this.load(this.lastOptions);
23198 * Calls the specified function for each of the Records in the cache.
23199 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23200 * Returning <em>false</em> aborts and exits the iteration.
23201 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23203 each : function(fn, scope){
23204 this.data.each(fn, scope);
23208 * Gets all records modified since the last commit. Modified records are persisted across load operations
23209 * (e.g., during paging).
23210 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23212 getModifiedRecords : function(){
23213 return this.modified;
23217 createFilterFn : function(property, value, anyMatch){
23218 if(!value.exec){ // not a regex
23219 value = String(value);
23220 if(value.length == 0){
23223 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23225 return function(r){
23226 return value.test(r.data[property]);
23231 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23232 * @param {String} property A field on your records
23233 * @param {Number} start The record index to start at (defaults to 0)
23234 * @param {Number} end The last record index to include (defaults to length - 1)
23235 * @return {Number} The sum
23237 sum : function(property, start, end){
23238 var rs = this.data.items, v = 0;
23239 start = start || 0;
23240 end = (end || end === 0) ? end : rs.length-1;
23242 for(var i = start; i <= end; i++){
23243 v += (rs[i].data[property] || 0);
23249 * Filter the records by a specified property.
23250 * @param {String} field A field on your records
23251 * @param {String/RegExp} value Either a string that the field
23252 * should start with or a RegExp to test against the field
23253 * @param {Boolean} anyMatch True to match any part not just the beginning
23255 filter : function(property, value, anyMatch){
23256 var fn = this.createFilterFn(property, value, anyMatch);
23257 return fn ? this.filterBy(fn) : this.clearFilter();
23261 * Filter by a function. The specified function will be called with each
23262 * record in this data source. If the function returns true the record is included,
23263 * otherwise it is filtered.
23264 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23265 * @param {Object} scope (optional) The scope of the function (defaults to this)
23267 filterBy : function(fn, scope){
23268 this.snapshot = this.snapshot || this.data;
23269 this.data = this.queryBy(fn, scope||this);
23270 this.fireEvent("datachanged", this);
23274 * Query the records by a specified property.
23275 * @param {String} field A field on your records
23276 * @param {String/RegExp} value Either a string that the field
23277 * should start with or a RegExp to test against the field
23278 * @param {Boolean} anyMatch True to match any part not just the beginning
23279 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23281 query : function(property, value, anyMatch){
23282 var fn = this.createFilterFn(property, value, anyMatch);
23283 return fn ? this.queryBy(fn) : this.data.clone();
23287 * Query by a function. The specified function will be called with each
23288 * record in this data source. If the function returns true the record is included
23290 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23291 * @param {Object} scope (optional) The scope of the function (defaults to this)
23292 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23294 queryBy : function(fn, scope){
23295 var data = this.snapshot || this.data;
23296 return data.filterBy(fn, scope||this);
23300 * Collects unique values for a particular dataIndex from this store.
23301 * @param {String} dataIndex The property to collect
23302 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23303 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23304 * @return {Array} An array of the unique values
23306 collect : function(dataIndex, allowNull, bypassFilter){
23307 var d = (bypassFilter === true && this.snapshot) ?
23308 this.snapshot.items : this.data.items;
23309 var v, sv, r = [], l = {};
23310 for(var i = 0, len = d.length; i < len; i++){
23311 v = d[i].data[dataIndex];
23313 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23322 * Revert to a view of the Record cache with no filtering applied.
23323 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23325 clearFilter : function(suppressEvent){
23326 if(this.snapshot && this.snapshot != this.data){
23327 this.data = this.snapshot;
23328 delete this.snapshot;
23329 if(suppressEvent !== true){
23330 this.fireEvent("datachanged", this);
23336 afterEdit : function(record){
23337 if(this.modified.indexOf(record) == -1){
23338 this.modified.push(record);
23340 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23344 afterReject : function(record){
23345 this.modified.remove(record);
23346 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23350 afterCommit : function(record){
23351 this.modified.remove(record);
23352 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23356 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23357 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23359 commitChanges : function(){
23360 var m = this.modified.slice(0);
23361 this.modified = [];
23362 for(var i = 0, len = m.length; i < len; i++){
23368 * Cancel outstanding changes on all changed records.
23370 rejectChanges : function(){
23371 var m = this.modified.slice(0);
23372 this.modified = [];
23373 for(var i = 0, len = m.length; i < len; i++){
23378 onMetaChange : function(meta, rtype, o){
23379 this.recordType = rtype;
23380 this.fields = rtype.prototype.fields;
23381 delete this.snapshot;
23382 this.sortInfo = meta.sortInfo || this.sortInfo;
23383 this.modified = [];
23384 this.fireEvent('metachange', this, this.reader.meta);
23387 moveIndex : function(data, type)
23389 var index = this.indexOf(data);
23391 var newIndex = index + type;
23395 this.insert(newIndex, data);
23400 * Ext JS Library 1.1.1
23401 * Copyright(c) 2006-2007, Ext JS, LLC.
23403 * Originally Released Under LGPL - original licence link has changed is not relivant.
23406 * <script type="text/javascript">
23410 * @class Roo.data.SimpleStore
23411 * @extends Roo.data.Store
23412 * Small helper class to make creating Stores from Array data easier.
23413 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23414 * @cfg {Array} fields An array of field definition objects, or field name strings.
23415 * @cfg {Array} data The multi-dimensional array of data
23417 * @param {Object} config
23419 Roo.data.SimpleStore = function(config){
23420 Roo.data.SimpleStore.superclass.constructor.call(this, {
23422 reader: new Roo.data.ArrayReader({
23425 Roo.data.Record.create(config.fields)
23427 proxy : new Roo.data.MemoryProxy(config.data)
23431 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23433 * Ext JS Library 1.1.1
23434 * Copyright(c) 2006-2007, Ext JS, LLC.
23436 * Originally Released Under LGPL - original licence link has changed is not relivant.
23439 * <script type="text/javascript">
23444 * @extends Roo.data.Store
23445 * @class Roo.data.JsonStore
23446 * Small helper class to make creating Stores for JSON data easier. <br/>
23448 var store = new Roo.data.JsonStore({
23449 url: 'get-images.php',
23451 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23454 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23455 * JsonReader and HttpProxy (unless inline data is provided).</b>
23456 * @cfg {Array} fields An array of field definition objects, or field name strings.
23458 * @param {Object} config
23460 Roo.data.JsonStore = function(c){
23461 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23462 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23463 reader: new Roo.data.JsonReader(c, c.fields)
23466 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23468 * Ext JS Library 1.1.1
23469 * Copyright(c) 2006-2007, Ext JS, LLC.
23471 * Originally Released Under LGPL - original licence link has changed is not relivant.
23474 * <script type="text/javascript">
23478 Roo.data.Field = function(config){
23479 if(typeof config == "string"){
23480 config = {name: config};
23482 Roo.apply(this, config);
23485 this.type = "auto";
23488 var st = Roo.data.SortTypes;
23489 // named sortTypes are supported, here we look them up
23490 if(typeof this.sortType == "string"){
23491 this.sortType = st[this.sortType];
23494 // set default sortType for strings and dates
23495 if(!this.sortType){
23498 this.sortType = st.asUCString;
23501 this.sortType = st.asDate;
23504 this.sortType = st.none;
23509 var stripRe = /[\$,%]/g;
23511 // prebuilt conversion function for this field, instead of
23512 // switching every time we're reading a value
23514 var cv, dateFormat = this.dateFormat;
23519 cv = function(v){ return v; };
23522 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23526 return v !== undefined && v !== null && v !== '' ?
23527 parseInt(String(v).replace(stripRe, ""), 10) : '';
23532 return v !== undefined && v !== null && v !== '' ?
23533 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23538 cv = function(v){ return v === true || v === "true" || v == 1; };
23545 if(v instanceof Date){
23549 if(dateFormat == "timestamp"){
23550 return new Date(v*1000);
23552 return Date.parseDate(v, dateFormat);
23554 var parsed = Date.parse(v);
23555 return parsed ? new Date(parsed) : null;
23564 Roo.data.Field.prototype = {
23572 * Ext JS Library 1.1.1
23573 * Copyright(c) 2006-2007, Ext JS, LLC.
23575 * Originally Released Under LGPL - original licence link has changed is not relivant.
23578 * <script type="text/javascript">
23581 // Base class for reading structured data from a data source. This class is intended to be
23582 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23585 * @class Roo.data.DataReader
23586 * Base class for reading structured data from a data source. This class is intended to be
23587 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23590 Roo.data.DataReader = function(meta, recordType){
23594 this.recordType = recordType instanceof Array ?
23595 Roo.data.Record.create(recordType) : recordType;
23598 Roo.data.DataReader.prototype = {
23600 * Create an empty record
23601 * @param {Object} data (optional) - overlay some values
23602 * @return {Roo.data.Record} record created.
23604 newRow : function(d) {
23606 this.recordType.prototype.fields.each(function(c) {
23608 case 'int' : da[c.name] = 0; break;
23609 case 'date' : da[c.name] = new Date(); break;
23610 case 'float' : da[c.name] = 0.0; break;
23611 case 'boolean' : da[c.name] = false; break;
23612 default : da[c.name] = ""; break;
23616 return new this.recordType(Roo.apply(da, d));
23621 * Ext JS Library 1.1.1
23622 * Copyright(c) 2006-2007, Ext JS, LLC.
23624 * Originally Released Under LGPL - original licence link has changed is not relivant.
23627 * <script type="text/javascript">
23631 * @class Roo.data.DataProxy
23632 * @extends Roo.data.Observable
23633 * This class is an abstract base class for implementations which provide retrieval of
23634 * unformatted data objects.<br>
23636 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23637 * (of the appropriate type which knows how to parse the data object) to provide a block of
23638 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23640 * Custom implementations must implement the load method as described in
23641 * {@link Roo.data.HttpProxy#load}.
23643 Roo.data.DataProxy = function(){
23646 * @event beforeload
23647 * Fires before a network request is made to retrieve a data object.
23648 * @param {Object} This DataProxy object.
23649 * @param {Object} params The params parameter to the load function.
23654 * Fires before the load method's callback is called.
23655 * @param {Object} This DataProxy object.
23656 * @param {Object} o The data object.
23657 * @param {Object} arg The callback argument object passed to the load function.
23661 * @event loadexception
23662 * Fires if an Exception occurs during data retrieval.
23663 * @param {Object} This DataProxy object.
23664 * @param {Object} o The data object.
23665 * @param {Object} arg The callback argument object passed to the load function.
23666 * @param {Object} e The Exception.
23668 loadexception : true
23670 Roo.data.DataProxy.superclass.constructor.call(this);
23673 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23676 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23680 * Ext JS Library 1.1.1
23681 * Copyright(c) 2006-2007, Ext JS, LLC.
23683 * Originally Released Under LGPL - original licence link has changed is not relivant.
23686 * <script type="text/javascript">
23689 * @class Roo.data.MemoryProxy
23690 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23691 * to the Reader when its load method is called.
23693 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23695 Roo.data.MemoryProxy = function(data){
23699 Roo.data.MemoryProxy.superclass.constructor.call(this);
23703 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23706 * Load data from the requested source (in this case an in-memory
23707 * data object passed to the constructor), read the data object into
23708 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23709 * process that block using the passed callback.
23710 * @param {Object} params This parameter is not used by the MemoryProxy class.
23711 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23712 * object into a block of Roo.data.Records.
23713 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23714 * The function must be passed <ul>
23715 * <li>The Record block object</li>
23716 * <li>The "arg" argument from the load function</li>
23717 * <li>A boolean success indicator</li>
23719 * @param {Object} scope The scope in which to call the callback
23720 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23722 load : function(params, reader, callback, scope, arg){
23723 params = params || {};
23726 result = reader.readRecords(this.data);
23728 this.fireEvent("loadexception", this, arg, null, e);
23729 callback.call(scope, null, arg, false);
23732 callback.call(scope, result, arg, true);
23736 update : function(params, records){
23741 * Ext JS Library 1.1.1
23742 * Copyright(c) 2006-2007, Ext JS, LLC.
23744 * Originally Released Under LGPL - original licence link has changed is not relivant.
23747 * <script type="text/javascript">
23750 * @class Roo.data.HttpProxy
23751 * @extends Roo.data.DataProxy
23752 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23753 * configured to reference a certain URL.<br><br>
23755 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23756 * from which the running page was served.<br><br>
23758 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23760 * Be aware that to enable the browser to parse an XML document, the server must set
23761 * the Content-Type header in the HTTP response to "text/xml".
23763 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23764 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23765 * will be used to make the request.
23767 Roo.data.HttpProxy = function(conn){
23768 Roo.data.HttpProxy.superclass.constructor.call(this);
23769 // is conn a conn config or a real conn?
23771 this.useAjax = !conn || !conn.events;
23775 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23776 // thse are take from connection...
23779 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23782 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23783 * extra parameters to each request made by this object. (defaults to undefined)
23786 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23787 * to each request made by this object. (defaults to undefined)
23790 * @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)
23793 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23796 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23802 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23806 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23807 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23808 * a finer-grained basis than the DataProxy events.
23810 getConnection : function(){
23811 return this.useAjax ? Roo.Ajax : this.conn;
23815 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23816 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23817 * process that block using the passed callback.
23818 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23819 * for the request to the remote server.
23820 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23821 * object into a block of Roo.data.Records.
23822 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23823 * The function must be passed <ul>
23824 * <li>The Record block object</li>
23825 * <li>The "arg" argument from the load function</li>
23826 * <li>A boolean success indicator</li>
23828 * @param {Object} scope The scope in which to call the callback
23829 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23831 load : function(params, reader, callback, scope, arg){
23832 if(this.fireEvent("beforeload", this, params) !== false){
23834 params : params || {},
23836 callback : callback,
23841 callback : this.loadResponse,
23845 Roo.applyIf(o, this.conn);
23846 if(this.activeRequest){
23847 Roo.Ajax.abort(this.activeRequest);
23849 this.activeRequest = Roo.Ajax.request(o);
23851 this.conn.request(o);
23854 callback.call(scope||this, null, arg, false);
23859 loadResponse : function(o, success, response){
23860 delete this.activeRequest;
23862 this.fireEvent("loadexception", this, o, response);
23863 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23868 result = o.reader.read(response);
23870 this.fireEvent("loadexception", this, o, response, e);
23871 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23875 this.fireEvent("load", this, o, o.request.arg);
23876 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23880 update : function(dataSet){
23885 updateResponse : function(dataSet){
23890 * Ext JS Library 1.1.1
23891 * Copyright(c) 2006-2007, Ext JS, LLC.
23893 * Originally Released Under LGPL - original licence link has changed is not relivant.
23896 * <script type="text/javascript">
23900 * @class Roo.data.ScriptTagProxy
23901 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23902 * other than the originating domain of the running page.<br><br>
23904 * <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
23905 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23907 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23908 * source code that is used as the source inside a <script> tag.<br><br>
23910 * In order for the browser to process the returned data, the server must wrap the data object
23911 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23912 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23913 * depending on whether the callback name was passed:
23916 boolean scriptTag = false;
23917 String cb = request.getParameter("callback");
23920 response.setContentType("text/javascript");
23922 response.setContentType("application/x-json");
23924 Writer out = response.getWriter();
23926 out.write(cb + "(");
23928 out.print(dataBlock.toJsonString());
23935 * @param {Object} config A configuration object.
23937 Roo.data.ScriptTagProxy = function(config){
23938 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23939 Roo.apply(this, config);
23940 this.head = document.getElementsByTagName("head")[0];
23943 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23945 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23947 * @cfg {String} url The URL from which to request the data object.
23950 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23954 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23955 * the server the name of the callback function set up by the load call to process the returned data object.
23956 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23957 * javascript output which calls this named function passing the data object as its only parameter.
23959 callbackParam : "callback",
23961 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23962 * name to the request.
23967 * Load data from the configured URL, read the data object into
23968 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23969 * process that block using the passed callback.
23970 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23971 * for the request to the remote server.
23972 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23973 * object into a block of Roo.data.Records.
23974 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23975 * The function must be passed <ul>
23976 * <li>The Record block object</li>
23977 * <li>The "arg" argument from the load function</li>
23978 * <li>A boolean success indicator</li>
23980 * @param {Object} scope The scope in which to call the callback
23981 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23983 load : function(params, reader, callback, scope, arg){
23984 if(this.fireEvent("beforeload", this, params) !== false){
23986 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23988 var url = this.url;
23989 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23991 url += "&_dc=" + (new Date().getTime());
23993 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
23996 cb : "stcCallback"+transId,
23997 scriptId : "stcScript"+transId,
24001 callback : callback,
24007 window[trans.cb] = function(o){
24008 conn.handleResponse(o, trans);
24011 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24013 if(this.autoAbort !== false){
24017 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24019 var script = document.createElement("script");
24020 script.setAttribute("src", url);
24021 script.setAttribute("type", "text/javascript");
24022 script.setAttribute("id", trans.scriptId);
24023 this.head.appendChild(script);
24025 this.trans = trans;
24027 callback.call(scope||this, null, arg, false);
24032 isLoading : function(){
24033 return this.trans ? true : false;
24037 * Abort the current server request.
24039 abort : function(){
24040 if(this.isLoading()){
24041 this.destroyTrans(this.trans);
24046 destroyTrans : function(trans, isLoaded){
24047 this.head.removeChild(document.getElementById(trans.scriptId));
24048 clearTimeout(trans.timeoutId);
24050 window[trans.cb] = undefined;
24052 delete window[trans.cb];
24055 // if hasn't been loaded, wait for load to remove it to prevent script error
24056 window[trans.cb] = function(){
24057 window[trans.cb] = undefined;
24059 delete window[trans.cb];
24066 handleResponse : function(o, trans){
24067 this.trans = false;
24068 this.destroyTrans(trans, true);
24071 result = trans.reader.readRecords(o);
24073 this.fireEvent("loadexception", this, o, trans.arg, e);
24074 trans.callback.call(trans.scope||window, null, trans.arg, false);
24077 this.fireEvent("load", this, o, trans.arg);
24078 trans.callback.call(trans.scope||window, result, trans.arg, true);
24082 handleFailure : function(trans){
24083 this.trans = false;
24084 this.destroyTrans(trans, false);
24085 this.fireEvent("loadexception", this, null, trans.arg);
24086 trans.callback.call(trans.scope||window, null, trans.arg, false);
24090 * Ext JS Library 1.1.1
24091 * Copyright(c) 2006-2007, Ext JS, LLC.
24093 * Originally Released Under LGPL - original licence link has changed is not relivant.
24096 * <script type="text/javascript">
24100 * @class Roo.data.JsonReader
24101 * @extends Roo.data.DataReader
24102 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24103 * based on mappings in a provided Roo.data.Record constructor.
24105 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24106 * in the reply previously.
24111 var RecordDef = Roo.data.Record.create([
24112 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24113 {name: 'occupation'} // This field will use "occupation" as the mapping.
24115 var myReader = new Roo.data.JsonReader({
24116 totalProperty: "results", // The property which contains the total dataset size (optional)
24117 root: "rows", // The property which contains an Array of row objects
24118 id: "id" // The property within each row object that provides an ID for the record (optional)
24122 * This would consume a JSON file like this:
24124 { 'results': 2, 'rows': [
24125 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24126 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24129 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24130 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24131 * paged from the remote server.
24132 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24133 * @cfg {String} root name of the property which contains the Array of row objects.
24134 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24135 * @cfg {Array} fields Array of field definition objects
24137 * Create a new JsonReader
24138 * @param {Object} meta Metadata configuration options
24139 * @param {Object} recordType Either an Array of field definition objects,
24140 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24142 Roo.data.JsonReader = function(meta, recordType){
24145 // set some defaults:
24146 Roo.applyIf(meta, {
24147 totalProperty: 'total',
24148 successProperty : 'success',
24153 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24155 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24158 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24159 * Used by Store query builder to append _requestMeta to params.
24162 metaFromRemote : false,
24164 * This method is only used by a DataProxy which has retrieved data from a remote server.
24165 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24166 * @return {Object} data A data block which is used by an Roo.data.Store object as
24167 * a cache of Roo.data.Records.
24169 read : function(response){
24170 var json = response.responseText;
24172 var o = /* eval:var:o */ eval("("+json+")");
24174 throw {message: "JsonReader.read: Json object not found"};
24180 this.metaFromRemote = true;
24181 this.meta = o.metaData;
24182 this.recordType = Roo.data.Record.create(o.metaData.fields);
24183 this.onMetaChange(this.meta, this.recordType, o);
24185 return this.readRecords(o);
24188 // private function a store will implement
24189 onMetaChange : function(meta, recordType, o){
24196 simpleAccess: function(obj, subsc) {
24203 getJsonAccessor: function(){
24205 return function(expr) {
24207 return(re.test(expr))
24208 ? new Function("obj", "return obj." + expr)
24213 return Roo.emptyFn;
24218 * Create a data block containing Roo.data.Records from an XML document.
24219 * @param {Object} o An object which contains an Array of row objects in the property specified
24220 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24221 * which contains the total size of the dataset.
24222 * @return {Object} data A data block which is used by an Roo.data.Store object as
24223 * a cache of Roo.data.Records.
24225 readRecords : function(o){
24227 * After any data loads, the raw JSON data is available for further custom processing.
24231 var s = this.meta, Record = this.recordType,
24232 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24234 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24236 if(s.totalProperty) {
24237 this.getTotal = this.getJsonAccessor(s.totalProperty);
24239 if(s.successProperty) {
24240 this.getSuccess = this.getJsonAccessor(s.successProperty);
24242 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24244 var g = this.getJsonAccessor(s.id);
24245 this.getId = function(rec) {
24247 return (r === undefined || r === "") ? null : r;
24250 this.getId = function(){return null;};
24253 for(var jj = 0; jj < fl; jj++){
24255 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24256 this.ef[jj] = this.getJsonAccessor(map);
24260 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24261 if(s.totalProperty){
24262 var vt = parseInt(this.getTotal(o), 10);
24267 if(s.successProperty){
24268 var vs = this.getSuccess(o);
24269 if(vs === false || vs === 'false'){
24274 for(var i = 0; i < c; i++){
24277 var id = this.getId(n);
24278 for(var j = 0; j < fl; j++){
24280 var v = this.ef[j](n);
24282 Roo.log('missing convert for ' + f.name);
24286 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24288 var record = new Record(values, id);
24290 records[i] = record;
24296 totalRecords : totalRecords
24301 * Ext JS Library 1.1.1
24302 * Copyright(c) 2006-2007, Ext JS, LLC.
24304 * Originally Released Under LGPL - original licence link has changed is not relivant.
24307 * <script type="text/javascript">
24311 * @class Roo.data.XmlReader
24312 * @extends Roo.data.DataReader
24313 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24314 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24316 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24317 * header in the HTTP response must be set to "text/xml".</em>
24321 var RecordDef = Roo.data.Record.create([
24322 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24323 {name: 'occupation'} // This field will use "occupation" as the mapping.
24325 var myReader = new Roo.data.XmlReader({
24326 totalRecords: "results", // The element which contains the total dataset size (optional)
24327 record: "row", // The repeated element which contains row information
24328 id: "id" // The element within the row that provides an ID for the record (optional)
24332 * This would consume an XML file like this:
24336 <results>2</results>
24339 <name>Bill</name>
24340 <occupation>Gardener</occupation>
24344 <name>Ben</name>
24345 <occupation>Horticulturalist</occupation>
24349 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24350 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24351 * paged from the remote server.
24352 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24353 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24354 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24355 * a record identifier value.
24357 * Create a new XmlReader
24358 * @param {Object} meta Metadata configuration options
24359 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24360 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24361 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24363 Roo.data.XmlReader = function(meta, recordType){
24365 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24367 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24369 * This method is only used by a DataProxy which has retrieved data from a remote server.
24370 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24371 * to contain a method called 'responseXML' that returns an XML document object.
24372 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24373 * a cache of Roo.data.Records.
24375 read : function(response){
24376 var doc = response.responseXML;
24378 throw {message: "XmlReader.read: XML Document not available"};
24380 return this.readRecords(doc);
24384 * Create a data block containing Roo.data.Records from an XML document.
24385 * @param {Object} doc A parsed XML document.
24386 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24387 * a cache of Roo.data.Records.
24389 readRecords : function(doc){
24391 * After any data loads/reads, the raw XML Document is available for further custom processing.
24392 * @type XMLDocument
24394 this.xmlData = doc;
24395 var root = doc.documentElement || doc;
24396 var q = Roo.DomQuery;
24397 var recordType = this.recordType, fields = recordType.prototype.fields;
24398 var sid = this.meta.id;
24399 var totalRecords = 0, success = true;
24400 if(this.meta.totalRecords){
24401 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24404 if(this.meta.success){
24405 var sv = q.selectValue(this.meta.success, root, true);
24406 success = sv !== false && sv !== 'false';
24409 var ns = q.select(this.meta.record, root);
24410 for(var i = 0, len = ns.length; i < len; i++) {
24413 var id = sid ? q.selectValue(sid, n) : undefined;
24414 for(var j = 0, jlen = fields.length; j < jlen; j++){
24415 var f = fields.items[j];
24416 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24418 values[f.name] = v;
24420 var record = new recordType(values, id);
24422 records[records.length] = record;
24428 totalRecords : totalRecords || records.length
24433 * Ext JS Library 1.1.1
24434 * Copyright(c) 2006-2007, Ext JS, LLC.
24436 * Originally Released Under LGPL - original licence link has changed is not relivant.
24439 * <script type="text/javascript">
24443 * @class Roo.data.ArrayReader
24444 * @extends Roo.data.DataReader
24445 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24446 * Each element of that Array represents a row of data fields. The
24447 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24448 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24452 var RecordDef = Roo.data.Record.create([
24453 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24454 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24456 var myReader = new Roo.data.ArrayReader({
24457 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24461 * This would consume an Array like this:
24463 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24465 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24467 * Create a new JsonReader
24468 * @param {Object} meta Metadata configuration options.
24469 * @param {Object} recordType Either an Array of field definition objects
24470 * as specified to {@link Roo.data.Record#create},
24471 * or an {@link Roo.data.Record} object
24472 * created using {@link Roo.data.Record#create}.
24474 Roo.data.ArrayReader = function(meta, recordType){
24475 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24478 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24480 * Create a data block containing Roo.data.Records from an XML document.
24481 * @param {Object} o An Array of row objects which represents the dataset.
24482 * @return {Object} data A data block which is used by an Roo.data.Store object as
24483 * a cache of Roo.data.Records.
24485 readRecords : function(o){
24486 var sid = this.meta ? this.meta.id : null;
24487 var recordType = this.recordType, fields = recordType.prototype.fields;
24490 for(var i = 0; i < root.length; i++){
24493 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24494 for(var j = 0, jlen = fields.length; j < jlen; j++){
24495 var f = fields.items[j];
24496 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24497 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24499 values[f.name] = v;
24501 var record = new recordType(values, id);
24503 records[records.length] = record;
24507 totalRecords : records.length
24512 * Ext JS Library 1.1.1
24513 * Copyright(c) 2006-2007, Ext JS, LLC.
24515 * Originally Released Under LGPL - original licence link has changed is not relivant.
24518 * <script type="text/javascript">
24523 * @class Roo.data.Tree
24524 * @extends Roo.util.Observable
24525 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24526 * in the tree have most standard DOM functionality.
24528 * @param {Node} root (optional) The root node
24530 Roo.data.Tree = function(root){
24531 this.nodeHash = {};
24533 * The root node for this tree
24538 this.setRootNode(root);
24543 * Fires when a new child node is appended to a node in this tree.
24544 * @param {Tree} tree The owner tree
24545 * @param {Node} parent The parent node
24546 * @param {Node} node The newly appended node
24547 * @param {Number} index The index of the newly appended node
24552 * Fires when a child node is removed from a node in this tree.
24553 * @param {Tree} tree The owner tree
24554 * @param {Node} parent The parent node
24555 * @param {Node} node The child node removed
24560 * Fires when a node is moved to a new location in the tree
24561 * @param {Tree} tree The owner tree
24562 * @param {Node} node The node moved
24563 * @param {Node} oldParent The old parent of this node
24564 * @param {Node} newParent The new parent of this node
24565 * @param {Number} index The index it was moved to
24570 * Fires when a new child node is inserted in a node in this tree.
24571 * @param {Tree} tree The owner tree
24572 * @param {Node} parent The parent node
24573 * @param {Node} node The child node inserted
24574 * @param {Node} refNode The child node the node was inserted before
24578 * @event beforeappend
24579 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24580 * @param {Tree} tree The owner tree
24581 * @param {Node} parent The parent node
24582 * @param {Node} node The child node to be appended
24584 "beforeappend" : true,
24586 * @event beforeremove
24587 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24588 * @param {Tree} tree The owner tree
24589 * @param {Node} parent The parent node
24590 * @param {Node} node The child node to be removed
24592 "beforeremove" : true,
24594 * @event beforemove
24595 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24596 * @param {Tree} tree The owner tree
24597 * @param {Node} node The node being moved
24598 * @param {Node} oldParent The parent of the node
24599 * @param {Node} newParent The new parent the node is moving to
24600 * @param {Number} index The index it is being moved to
24602 "beforemove" : true,
24604 * @event beforeinsert
24605 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24606 * @param {Tree} tree The owner tree
24607 * @param {Node} parent The parent node
24608 * @param {Node} node The child node to be inserted
24609 * @param {Node} refNode The child node the node is being inserted before
24611 "beforeinsert" : true
24614 Roo.data.Tree.superclass.constructor.call(this);
24617 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24618 pathSeparator: "/",
24620 proxyNodeEvent : function(){
24621 return this.fireEvent.apply(this, arguments);
24625 * Returns the root node for this tree.
24628 getRootNode : function(){
24633 * Sets the root node for this tree.
24634 * @param {Node} node
24637 setRootNode : function(node){
24639 node.ownerTree = this;
24640 node.isRoot = true;
24641 this.registerNode(node);
24646 * Gets a node in this tree by its id.
24647 * @param {String} id
24650 getNodeById : function(id){
24651 return this.nodeHash[id];
24654 registerNode : function(node){
24655 this.nodeHash[node.id] = node;
24658 unregisterNode : function(node){
24659 delete this.nodeHash[node.id];
24662 toString : function(){
24663 return "[Tree"+(this.id?" "+this.id:"")+"]";
24668 * @class Roo.data.Node
24669 * @extends Roo.util.Observable
24670 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24671 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24673 * @param {Object} attributes The attributes/config for the node
24675 Roo.data.Node = function(attributes){
24677 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24680 this.attributes = attributes || {};
24681 this.leaf = this.attributes.leaf;
24683 * The node id. @type String
24685 this.id = this.attributes.id;
24687 this.id = Roo.id(null, "ynode-");
24688 this.attributes.id = this.id;
24693 * All child nodes of this node. @type Array
24695 this.childNodes = [];
24696 if(!this.childNodes.indexOf){ // indexOf is a must
24697 this.childNodes.indexOf = function(o){
24698 for(var i = 0, len = this.length; i < len; i++){
24707 * The parent node for this node. @type Node
24709 this.parentNode = null;
24711 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24713 this.firstChild = null;
24715 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24717 this.lastChild = null;
24719 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24721 this.previousSibling = null;
24723 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24725 this.nextSibling = null;
24730 * Fires when a new child node is appended
24731 * @param {Tree} tree The owner tree
24732 * @param {Node} this This node
24733 * @param {Node} node The newly appended node
24734 * @param {Number} index The index of the newly appended node
24739 * Fires when a child node is removed
24740 * @param {Tree} tree The owner tree
24741 * @param {Node} this This node
24742 * @param {Node} node The removed node
24747 * Fires when this node is moved to a new location in the tree
24748 * @param {Tree} tree The owner tree
24749 * @param {Node} this This node
24750 * @param {Node} oldParent The old parent of this node
24751 * @param {Node} newParent The new parent of this node
24752 * @param {Number} index The index it was moved to
24757 * Fires when a new child node is inserted.
24758 * @param {Tree} tree The owner tree
24759 * @param {Node} this This node
24760 * @param {Node} node The child node inserted
24761 * @param {Node} refNode The child node the node was inserted before
24765 * @event beforeappend
24766 * Fires before a new child is appended, return false to cancel the append.
24767 * @param {Tree} tree The owner tree
24768 * @param {Node} this This node
24769 * @param {Node} node The child node to be appended
24771 "beforeappend" : true,
24773 * @event beforeremove
24774 * Fires before a child is removed, return false to cancel the remove.
24775 * @param {Tree} tree The owner tree
24776 * @param {Node} this This node
24777 * @param {Node} node The child node to be removed
24779 "beforeremove" : true,
24781 * @event beforemove
24782 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24783 * @param {Tree} tree The owner tree
24784 * @param {Node} this This node
24785 * @param {Node} oldParent The parent of this node
24786 * @param {Node} newParent The new parent this node is moving to
24787 * @param {Number} index The index it is being moved to
24789 "beforemove" : true,
24791 * @event beforeinsert
24792 * Fires before a new child is inserted, return false to cancel the insert.
24793 * @param {Tree} tree The owner tree
24794 * @param {Node} this This node
24795 * @param {Node} node The child node to be inserted
24796 * @param {Node} refNode The child node the node is being inserted before
24798 "beforeinsert" : true
24800 this.listeners = this.attributes.listeners;
24801 Roo.data.Node.superclass.constructor.call(this);
24804 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24805 fireEvent : function(evtName){
24806 // first do standard event for this node
24807 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24810 // then bubble it up to the tree if the event wasn't cancelled
24811 var ot = this.getOwnerTree();
24813 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24821 * Returns true if this node is a leaf
24822 * @return {Boolean}
24824 isLeaf : function(){
24825 return this.leaf === true;
24829 setFirstChild : function(node){
24830 this.firstChild = node;
24834 setLastChild : function(node){
24835 this.lastChild = node;
24840 * Returns true if this node is the last child of its parent
24841 * @return {Boolean}
24843 isLast : function(){
24844 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24848 * Returns true if this node is the first child of its parent
24849 * @return {Boolean}
24851 isFirst : function(){
24852 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24855 hasChildNodes : function(){
24856 return !this.isLeaf() && this.childNodes.length > 0;
24860 * Insert node(s) as the last child node of this node.
24861 * @param {Node/Array} node The node or Array of nodes to append
24862 * @return {Node} The appended node if single append, or null if an array was passed
24864 appendChild : function(node){
24866 if(node instanceof Array){
24868 }else if(arguments.length > 1){
24871 // if passed an array or multiple args do them one by one
24873 for(var i = 0, len = multi.length; i < len; i++) {
24874 this.appendChild(multi[i]);
24877 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24880 var index = this.childNodes.length;
24881 var oldParent = node.parentNode;
24882 // it's a move, make sure we move it cleanly
24884 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24887 oldParent.removeChild(node);
24889 index = this.childNodes.length;
24891 this.setFirstChild(node);
24893 this.childNodes.push(node);
24894 node.parentNode = this;
24895 var ps = this.childNodes[index-1];
24897 node.previousSibling = ps;
24898 ps.nextSibling = node;
24900 node.previousSibling = null;
24902 node.nextSibling = null;
24903 this.setLastChild(node);
24904 node.setOwnerTree(this.getOwnerTree());
24905 this.fireEvent("append", this.ownerTree, this, node, index);
24907 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24914 * Removes a child node from this node.
24915 * @param {Node} node The node to remove
24916 * @return {Node} The removed node
24918 removeChild : function(node){
24919 var index = this.childNodes.indexOf(node);
24923 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24927 // remove it from childNodes collection
24928 this.childNodes.splice(index, 1);
24931 if(node.previousSibling){
24932 node.previousSibling.nextSibling = node.nextSibling;
24934 if(node.nextSibling){
24935 node.nextSibling.previousSibling = node.previousSibling;
24938 // update child refs
24939 if(this.firstChild == node){
24940 this.setFirstChild(node.nextSibling);
24942 if(this.lastChild == node){
24943 this.setLastChild(node.previousSibling);
24946 node.setOwnerTree(null);
24947 // clear any references from the node
24948 node.parentNode = null;
24949 node.previousSibling = null;
24950 node.nextSibling = null;
24951 this.fireEvent("remove", this.ownerTree, this, node);
24956 * Inserts the first node before the second node in this nodes childNodes collection.
24957 * @param {Node} node The node to insert
24958 * @param {Node} refNode The node to insert before (if null the node is appended)
24959 * @return {Node} The inserted node
24961 insertBefore : function(node, refNode){
24962 if(!refNode){ // like standard Dom, refNode can be null for append
24963 return this.appendChild(node);
24966 if(node == refNode){
24970 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24973 var index = this.childNodes.indexOf(refNode);
24974 var oldParent = node.parentNode;
24975 var refIndex = index;
24977 // when moving internally, indexes will change after remove
24978 if(oldParent == this && this.childNodes.indexOf(node) < index){
24982 // it's a move, make sure we move it cleanly
24984 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24987 oldParent.removeChild(node);
24990 this.setFirstChild(node);
24992 this.childNodes.splice(refIndex, 0, node);
24993 node.parentNode = this;
24994 var ps = this.childNodes[refIndex-1];
24996 node.previousSibling = ps;
24997 ps.nextSibling = node;
24999 node.previousSibling = null;
25001 node.nextSibling = refNode;
25002 refNode.previousSibling = node;
25003 node.setOwnerTree(this.getOwnerTree());
25004 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25006 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25012 * Returns the child node at the specified index.
25013 * @param {Number} index
25016 item : function(index){
25017 return this.childNodes[index];
25021 * Replaces one child node in this node with another.
25022 * @param {Node} newChild The replacement node
25023 * @param {Node} oldChild The node to replace
25024 * @return {Node} The replaced node
25026 replaceChild : function(newChild, oldChild){
25027 this.insertBefore(newChild, oldChild);
25028 this.removeChild(oldChild);
25033 * Returns the index of a child node
25034 * @param {Node} node
25035 * @return {Number} The index of the node or -1 if it was not found
25037 indexOf : function(child){
25038 return this.childNodes.indexOf(child);
25042 * Returns the tree this node is in.
25045 getOwnerTree : function(){
25046 // if it doesn't have one, look for one
25047 if(!this.ownerTree){
25051 this.ownerTree = p.ownerTree;
25057 return this.ownerTree;
25061 * Returns depth of this node (the root node has a depth of 0)
25064 getDepth : function(){
25067 while(p.parentNode){
25075 setOwnerTree : function(tree){
25076 // if it's move, we need to update everyone
25077 if(tree != this.ownerTree){
25078 if(this.ownerTree){
25079 this.ownerTree.unregisterNode(this);
25081 this.ownerTree = tree;
25082 var cs = this.childNodes;
25083 for(var i = 0, len = cs.length; i < len; i++) {
25084 cs[i].setOwnerTree(tree);
25087 tree.registerNode(this);
25093 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25094 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25095 * @return {String} The path
25097 getPath : function(attr){
25098 attr = attr || "id";
25099 var p = this.parentNode;
25100 var b = [this.attributes[attr]];
25102 b.unshift(p.attributes[attr]);
25105 var sep = this.getOwnerTree().pathSeparator;
25106 return sep + b.join(sep);
25110 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25111 * function call will be the scope provided or the current node. The arguments to the function
25112 * will be the args provided or the current node. If the function returns false at any point,
25113 * the bubble is stopped.
25114 * @param {Function} fn The function to call
25115 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25116 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25118 bubble : function(fn, scope, args){
25121 if(fn.call(scope || p, args || p) === false){
25129 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25130 * function call will be the scope provided or the current node. The arguments to the function
25131 * will be the args provided or the current node. If the function returns false at any point,
25132 * the cascade is stopped on that branch.
25133 * @param {Function} fn The function to call
25134 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25135 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25137 cascade : function(fn, scope, args){
25138 if(fn.call(scope || this, args || this) !== false){
25139 var cs = this.childNodes;
25140 for(var i = 0, len = cs.length; i < len; i++) {
25141 cs[i].cascade(fn, scope, args);
25147 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25148 * function call will be the scope provided or the current node. The arguments to the function
25149 * will be the args provided or the current node. If the function returns false at any point,
25150 * the iteration stops.
25151 * @param {Function} fn The function to call
25152 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25153 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25155 eachChild : function(fn, scope, args){
25156 var cs = this.childNodes;
25157 for(var i = 0, len = cs.length; i < len; i++) {
25158 if(fn.call(scope || this, args || cs[i]) === false){
25165 * Finds the first child that has the attribute with the specified value.
25166 * @param {String} attribute The attribute name
25167 * @param {Mixed} value The value to search for
25168 * @return {Node} The found child or null if none was found
25170 findChild : function(attribute, value){
25171 var cs = this.childNodes;
25172 for(var i = 0, len = cs.length; i < len; i++) {
25173 if(cs[i].attributes[attribute] == value){
25181 * Finds the first child by a custom function. The child matches if the function passed
25183 * @param {Function} fn
25184 * @param {Object} scope (optional)
25185 * @return {Node} The found child or null if none was found
25187 findChildBy : function(fn, scope){
25188 var cs = this.childNodes;
25189 for(var i = 0, len = cs.length; i < len; i++) {
25190 if(fn.call(scope||cs[i], cs[i]) === true){
25198 * Sorts this nodes children using the supplied sort function
25199 * @param {Function} fn
25200 * @param {Object} scope (optional)
25202 sort : function(fn, scope){
25203 var cs = this.childNodes;
25204 var len = cs.length;
25206 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25208 for(var i = 0; i < len; i++){
25210 n.previousSibling = cs[i-1];
25211 n.nextSibling = cs[i+1];
25213 this.setFirstChild(n);
25216 this.setLastChild(n);
25223 * Returns true if this node is an ancestor (at any point) of the passed node.
25224 * @param {Node} node
25225 * @return {Boolean}
25227 contains : function(node){
25228 return node.isAncestor(this);
25232 * Returns true if the passed node is an ancestor (at any point) of this node.
25233 * @param {Node} node
25234 * @return {Boolean}
25236 isAncestor : function(node){
25237 var p = this.parentNode;
25247 toString : function(){
25248 return "[Node"+(this.id?" "+this.id:"")+"]";
25252 * Ext JS Library 1.1.1
25253 * Copyright(c) 2006-2007, Ext JS, LLC.
25255 * Originally Released Under LGPL - original licence link has changed is not relivant.
25258 * <script type="text/javascript">
25263 * @extends Roo.Element
25264 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25265 * automatic maintaining of shadow/shim positions.
25266 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25267 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25268 * you can pass a string with a CSS class name. False turns off the shadow.
25269 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25270 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25271 * @cfg {String} cls CSS class to add to the element
25272 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25273 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25275 * @param {Object} config An object with config options.
25276 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25279 Roo.Layer = function(config, existingEl){
25280 config = config || {};
25281 var dh = Roo.DomHelper;
25282 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25284 this.dom = Roo.getDom(existingEl);
25287 var o = config.dh || {tag: "div", cls: "x-layer"};
25288 this.dom = dh.append(pel, o);
25291 this.addClass(config.cls);
25293 this.constrain = config.constrain !== false;
25294 this.visibilityMode = Roo.Element.VISIBILITY;
25296 this.id = this.dom.id = config.id;
25298 this.id = Roo.id(this.dom);
25300 this.zindex = config.zindex || this.getZIndex();
25301 this.position("absolute", this.zindex);
25303 this.shadowOffset = config.shadowOffset || 4;
25304 this.shadow = new Roo.Shadow({
25305 offset : this.shadowOffset,
25306 mode : config.shadow
25309 this.shadowOffset = 0;
25311 this.useShim = config.shim !== false && Roo.useShims;
25312 this.useDisplay = config.useDisplay;
25316 var supr = Roo.Element.prototype;
25318 // shims are shared among layer to keep from having 100 iframes
25321 Roo.extend(Roo.Layer, Roo.Element, {
25323 getZIndex : function(){
25324 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25327 getShim : function(){
25334 var shim = shims.shift();
25336 shim = this.createShim();
25337 shim.enableDisplayMode('block');
25338 shim.dom.style.display = 'none';
25339 shim.dom.style.visibility = 'visible';
25341 var pn = this.dom.parentNode;
25342 if(shim.dom.parentNode != pn){
25343 pn.insertBefore(shim.dom, this.dom);
25345 shim.setStyle('z-index', this.getZIndex()-2);
25350 hideShim : function(){
25352 this.shim.setDisplayed(false);
25353 shims.push(this.shim);
25358 disableShadow : function(){
25360 this.shadowDisabled = true;
25361 this.shadow.hide();
25362 this.lastShadowOffset = this.shadowOffset;
25363 this.shadowOffset = 0;
25367 enableShadow : function(show){
25369 this.shadowDisabled = false;
25370 this.shadowOffset = this.lastShadowOffset;
25371 delete this.lastShadowOffset;
25379 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25380 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25381 sync : function(doShow){
25382 var sw = this.shadow;
25383 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25384 var sh = this.getShim();
25386 var w = this.getWidth(),
25387 h = this.getHeight();
25389 var l = this.getLeft(true),
25390 t = this.getTop(true);
25392 if(sw && !this.shadowDisabled){
25393 if(doShow && !sw.isVisible()){
25396 sw.realign(l, t, w, h);
25402 // fit the shim behind the shadow, so it is shimmed too
25403 var a = sw.adjusts, s = sh.dom.style;
25404 s.left = (Math.min(l, l+a.l))+"px";
25405 s.top = (Math.min(t, t+a.t))+"px";
25406 s.width = (w+a.w)+"px";
25407 s.height = (h+a.h)+"px";
25414 sh.setLeftTop(l, t);
25421 destroy : function(){
25424 this.shadow.hide();
25426 this.removeAllListeners();
25427 var pn = this.dom.parentNode;
25429 pn.removeChild(this.dom);
25431 Roo.Element.uncache(this.id);
25434 remove : function(){
25439 beginUpdate : function(){
25440 this.updating = true;
25444 endUpdate : function(){
25445 this.updating = false;
25450 hideUnders : function(negOffset){
25452 this.shadow.hide();
25458 constrainXY : function(){
25459 if(this.constrain){
25460 var vw = Roo.lib.Dom.getViewWidth(),
25461 vh = Roo.lib.Dom.getViewHeight();
25462 var s = Roo.get(document).getScroll();
25464 var xy = this.getXY();
25465 var x = xy[0], y = xy[1];
25466 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25467 // only move it if it needs it
25469 // first validate right/bottom
25470 if((x + w) > vw+s.left){
25471 x = vw - w - this.shadowOffset;
25474 if((y + h) > vh+s.top){
25475 y = vh - h - this.shadowOffset;
25478 // then make sure top/left isn't negative
25489 var ay = this.avoidY;
25490 if(y <= ay && (y+h) >= ay){
25496 supr.setXY.call(this, xy);
25502 isVisible : function(){
25503 return this.visible;
25507 showAction : function(){
25508 this.visible = true; // track visibility to prevent getStyle calls
25509 if(this.useDisplay === true){
25510 this.setDisplayed("");
25511 }else if(this.lastXY){
25512 supr.setXY.call(this, this.lastXY);
25513 }else if(this.lastLT){
25514 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25519 hideAction : function(){
25520 this.visible = false;
25521 if(this.useDisplay === true){
25522 this.setDisplayed(false);
25524 this.setLeftTop(-10000,-10000);
25528 // overridden Element method
25529 setVisible : function(v, a, d, c, e){
25534 var cb = function(){
25539 }.createDelegate(this);
25540 supr.setVisible.call(this, true, true, d, cb, e);
25543 this.hideUnders(true);
25552 }.createDelegate(this);
25554 supr.setVisible.call(this, v, a, d, cb, e);
25563 storeXY : function(xy){
25564 delete this.lastLT;
25568 storeLeftTop : function(left, top){
25569 delete this.lastXY;
25570 this.lastLT = [left, top];
25574 beforeFx : function(){
25575 this.beforeAction();
25576 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25580 afterFx : function(){
25581 Roo.Layer.superclass.afterFx.apply(this, arguments);
25582 this.sync(this.isVisible());
25586 beforeAction : function(){
25587 if(!this.updating && this.shadow){
25588 this.shadow.hide();
25592 // overridden Element method
25593 setLeft : function(left){
25594 this.storeLeftTop(left, this.getTop(true));
25595 supr.setLeft.apply(this, arguments);
25599 setTop : function(top){
25600 this.storeLeftTop(this.getLeft(true), top);
25601 supr.setTop.apply(this, arguments);
25605 setLeftTop : function(left, top){
25606 this.storeLeftTop(left, top);
25607 supr.setLeftTop.apply(this, arguments);
25611 setXY : function(xy, a, d, c, e){
25613 this.beforeAction();
25615 var cb = this.createCB(c);
25616 supr.setXY.call(this, xy, a, d, cb, e);
25623 createCB : function(c){
25634 // overridden Element method
25635 setX : function(x, a, d, c, e){
25636 this.setXY([x, this.getY()], a, d, c, e);
25639 // overridden Element method
25640 setY : function(y, a, d, c, e){
25641 this.setXY([this.getX(), y], a, d, c, e);
25644 // overridden Element method
25645 setSize : function(w, h, a, d, c, e){
25646 this.beforeAction();
25647 var cb = this.createCB(c);
25648 supr.setSize.call(this, w, h, a, d, cb, e);
25654 // overridden Element method
25655 setWidth : function(w, a, d, c, e){
25656 this.beforeAction();
25657 var cb = this.createCB(c);
25658 supr.setWidth.call(this, w, a, d, cb, e);
25664 // overridden Element method
25665 setHeight : function(h, a, d, c, e){
25666 this.beforeAction();
25667 var cb = this.createCB(c);
25668 supr.setHeight.call(this, h, a, d, cb, e);
25674 // overridden Element method
25675 setBounds : function(x, y, w, h, a, d, c, e){
25676 this.beforeAction();
25677 var cb = this.createCB(c);
25679 this.storeXY([x, y]);
25680 supr.setXY.call(this, [x, y]);
25681 supr.setSize.call(this, w, h, a, d, cb, e);
25684 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25690 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25691 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25692 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25693 * @param {Number} zindex The new z-index to set
25694 * @return {this} The Layer
25696 setZIndex : function(zindex){
25697 this.zindex = zindex;
25698 this.setStyle("z-index", zindex + 2);
25700 this.shadow.setZIndex(zindex + 1);
25703 this.shim.setStyle("z-index", zindex);
25709 * Ext JS Library 1.1.1
25710 * Copyright(c) 2006-2007, Ext JS, LLC.
25712 * Originally Released Under LGPL - original licence link has changed is not relivant.
25715 * <script type="text/javascript">
25720 * @class Roo.Shadow
25721 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25722 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25723 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25725 * Create a new Shadow
25726 * @param {Object} config The config object
25728 Roo.Shadow = function(config){
25729 Roo.apply(this, config);
25730 if(typeof this.mode != "string"){
25731 this.mode = this.defaultMode;
25733 var o = this.offset, a = {h: 0};
25734 var rad = Math.floor(this.offset/2);
25735 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25741 a.l -= this.offset + rad;
25742 a.t -= this.offset + rad;
25753 a.l -= (this.offset - rad);
25754 a.t -= this.offset + rad;
25756 a.w -= (this.offset - rad)*2;
25767 a.l -= (this.offset - rad);
25768 a.t -= (this.offset - rad);
25770 a.w -= (this.offset + rad + 1);
25771 a.h -= (this.offset + rad);
25780 Roo.Shadow.prototype = {
25782 * @cfg {String} mode
25783 * The shadow display mode. Supports the following options:<br />
25784 * sides: Shadow displays on both sides and bottom only<br />
25785 * frame: Shadow displays equally on all four sides<br />
25786 * drop: Traditional bottom-right drop shadow (default)
25789 * @cfg {String} offset
25790 * The number of pixels to offset the shadow from the element (defaults to 4)
25795 defaultMode: "drop",
25798 * Displays the shadow under the target element
25799 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25801 show : function(target){
25802 target = Roo.get(target);
25804 this.el = Roo.Shadow.Pool.pull();
25805 if(this.el.dom.nextSibling != target.dom){
25806 this.el.insertBefore(target);
25809 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25811 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25814 target.getLeft(true),
25815 target.getTop(true),
25819 this.el.dom.style.display = "block";
25823 * Returns true if the shadow is visible, else false
25825 isVisible : function(){
25826 return this.el ? true : false;
25830 * Direct alignment when values are already available. Show must be called at least once before
25831 * calling this method to ensure it is initialized.
25832 * @param {Number} left The target element left position
25833 * @param {Number} top The target element top position
25834 * @param {Number} width The target element width
25835 * @param {Number} height The target element height
25837 realign : function(l, t, w, h){
25841 var a = this.adjusts, d = this.el.dom, s = d.style;
25843 s.left = (l+a.l)+"px";
25844 s.top = (t+a.t)+"px";
25845 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25847 if(s.width != sws || s.height != shs){
25851 var cn = d.childNodes;
25852 var sww = Math.max(0, (sw-12))+"px";
25853 cn[0].childNodes[1].style.width = sww;
25854 cn[1].childNodes[1].style.width = sww;
25855 cn[2].childNodes[1].style.width = sww;
25856 cn[1].style.height = Math.max(0, (sh-12))+"px";
25862 * Hides this shadow
25866 this.el.dom.style.display = "none";
25867 Roo.Shadow.Pool.push(this.el);
25873 * Adjust the z-index of this shadow
25874 * @param {Number} zindex The new z-index
25876 setZIndex : function(z){
25879 this.el.setStyle("z-index", z);
25884 // Private utility class that manages the internal Shadow cache
25885 Roo.Shadow.Pool = function(){
25887 var markup = Roo.isIE ?
25888 '<div class="x-ie-shadow"></div>' :
25889 '<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>';
25892 var sh = p.shift();
25894 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25895 sh.autoBoxAdjust = false;
25900 push : function(sh){
25906 * Ext JS Library 1.1.1
25907 * Copyright(c) 2006-2007, Ext JS, LLC.
25909 * Originally Released Under LGPL - original licence link has changed is not relivant.
25912 * <script type="text/javascript">
25917 * @class Roo.SplitBar
25918 * @extends Roo.util.Observable
25919 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25923 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25924 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25925 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25926 split.minSize = 100;
25927 split.maxSize = 600;
25928 split.animate = true;
25929 split.on('moved', splitterMoved);
25932 * Create a new SplitBar
25933 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25934 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25935 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25936 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25937 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25938 position of the SplitBar).
25940 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25943 this.el = Roo.get(dragElement, true);
25944 this.el.dom.unselectable = "on";
25946 this.resizingEl = Roo.get(resizingElement, true);
25950 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25951 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25954 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25957 * The minimum size of the resizing element. (Defaults to 0)
25963 * The maximum size of the resizing element. (Defaults to 2000)
25966 this.maxSize = 2000;
25969 * Whether to animate the transition to the new size
25972 this.animate = false;
25975 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25978 this.useShim = false;
25983 if(!existingProxy){
25985 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25987 this.proxy = Roo.get(existingProxy).dom;
25990 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25993 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
25996 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
25999 this.dragSpecs = {};
26002 * @private The adapter to use to positon and resize elements
26004 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26005 this.adapter.init(this);
26007 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26009 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26010 this.el.addClass("x-splitbar-h");
26013 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26014 this.el.addClass("x-splitbar-v");
26020 * Fires when the splitter is moved (alias for {@link #event-moved})
26021 * @param {Roo.SplitBar} this
26022 * @param {Number} newSize the new width or height
26027 * Fires when the splitter is moved
26028 * @param {Roo.SplitBar} this
26029 * @param {Number} newSize the new width or height
26033 * @event beforeresize
26034 * Fires before the splitter is dragged
26035 * @param {Roo.SplitBar} this
26037 "beforeresize" : true,
26039 "beforeapply" : true
26042 Roo.util.Observable.call(this);
26045 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26046 onStartProxyDrag : function(x, y){
26047 this.fireEvent("beforeresize", this);
26049 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26051 o.enableDisplayMode("block");
26052 // all splitbars share the same overlay
26053 Roo.SplitBar.prototype.overlay = o;
26055 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26056 this.overlay.show();
26057 Roo.get(this.proxy).setDisplayed("block");
26058 var size = this.adapter.getElementSize(this);
26059 this.activeMinSize = this.getMinimumSize();;
26060 this.activeMaxSize = this.getMaximumSize();;
26061 var c1 = size - this.activeMinSize;
26062 var c2 = Math.max(this.activeMaxSize - size, 0);
26063 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26064 this.dd.resetConstraints();
26065 this.dd.setXConstraint(
26066 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26067 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26069 this.dd.setYConstraint(0, 0);
26071 this.dd.resetConstraints();
26072 this.dd.setXConstraint(0, 0);
26073 this.dd.setYConstraint(
26074 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26075 this.placement == Roo.SplitBar.TOP ? c2 : c1
26078 this.dragSpecs.startSize = size;
26079 this.dragSpecs.startPoint = [x, y];
26080 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26084 * @private Called after the drag operation by the DDProxy
26086 onEndProxyDrag : function(e){
26087 Roo.get(this.proxy).setDisplayed(false);
26088 var endPoint = Roo.lib.Event.getXY(e);
26090 this.overlay.hide();
26093 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26094 newSize = this.dragSpecs.startSize +
26095 (this.placement == Roo.SplitBar.LEFT ?
26096 endPoint[0] - this.dragSpecs.startPoint[0] :
26097 this.dragSpecs.startPoint[0] - endPoint[0]
26100 newSize = this.dragSpecs.startSize +
26101 (this.placement == Roo.SplitBar.TOP ?
26102 endPoint[1] - this.dragSpecs.startPoint[1] :
26103 this.dragSpecs.startPoint[1] - endPoint[1]
26106 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26107 if(newSize != this.dragSpecs.startSize){
26108 if(this.fireEvent('beforeapply', this, newSize) !== false){
26109 this.adapter.setElementSize(this, newSize);
26110 this.fireEvent("moved", this, newSize);
26111 this.fireEvent("resize", this, newSize);
26117 * Get the adapter this SplitBar uses
26118 * @return The adapter object
26120 getAdapter : function(){
26121 return this.adapter;
26125 * Set the adapter this SplitBar uses
26126 * @param {Object} adapter A SplitBar adapter object
26128 setAdapter : function(adapter){
26129 this.adapter = adapter;
26130 this.adapter.init(this);
26134 * Gets the minimum size for the resizing element
26135 * @return {Number} The minimum size
26137 getMinimumSize : function(){
26138 return this.minSize;
26142 * Sets the minimum size for the resizing element
26143 * @param {Number} minSize The minimum size
26145 setMinimumSize : function(minSize){
26146 this.minSize = minSize;
26150 * Gets the maximum size for the resizing element
26151 * @return {Number} The maximum size
26153 getMaximumSize : function(){
26154 return this.maxSize;
26158 * Sets the maximum size for the resizing element
26159 * @param {Number} maxSize The maximum size
26161 setMaximumSize : function(maxSize){
26162 this.maxSize = maxSize;
26166 * Sets the initialize size for the resizing element
26167 * @param {Number} size The initial size
26169 setCurrentSize : function(size){
26170 var oldAnimate = this.animate;
26171 this.animate = false;
26172 this.adapter.setElementSize(this, size);
26173 this.animate = oldAnimate;
26177 * Destroy this splitbar.
26178 * @param {Boolean} removeEl True to remove the element
26180 destroy : function(removeEl){
26182 this.shim.remove();
26185 this.proxy.parentNode.removeChild(this.proxy);
26193 * @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.
26195 Roo.SplitBar.createProxy = function(dir){
26196 var proxy = new Roo.Element(document.createElement("div"));
26197 proxy.unselectable();
26198 var cls = 'x-splitbar-proxy';
26199 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26200 document.body.appendChild(proxy.dom);
26205 * @class Roo.SplitBar.BasicLayoutAdapter
26206 * Default Adapter. It assumes the splitter and resizing element are not positioned
26207 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26209 Roo.SplitBar.BasicLayoutAdapter = function(){
26212 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26213 // do nothing for now
26214 init : function(s){
26218 * Called before drag operations to get the current size of the resizing element.
26219 * @param {Roo.SplitBar} s The SplitBar using this adapter
26221 getElementSize : function(s){
26222 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26223 return s.resizingEl.getWidth();
26225 return s.resizingEl.getHeight();
26230 * Called after drag operations to set the size of the resizing element.
26231 * @param {Roo.SplitBar} s The SplitBar using this adapter
26232 * @param {Number} newSize The new size to set
26233 * @param {Function} onComplete A function to be invoked when resizing is complete
26235 setElementSize : function(s, newSize, onComplete){
26236 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26238 s.resizingEl.setWidth(newSize);
26240 onComplete(s, newSize);
26243 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26248 s.resizingEl.setHeight(newSize);
26250 onComplete(s, newSize);
26253 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26260 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26261 * @extends Roo.SplitBar.BasicLayoutAdapter
26262 * Adapter that moves the splitter element to align with the resized sizing element.
26263 * Used with an absolute positioned SplitBar.
26264 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26265 * document.body, make sure you assign an id to the body element.
26267 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26268 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26269 this.container = Roo.get(container);
26272 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26273 init : function(s){
26274 this.basic.init(s);
26277 getElementSize : function(s){
26278 return this.basic.getElementSize(s);
26281 setElementSize : function(s, newSize, onComplete){
26282 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26285 moveSplitter : function(s){
26286 var yes = Roo.SplitBar;
26287 switch(s.placement){
26289 s.el.setX(s.resizingEl.getRight());
26292 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26295 s.el.setY(s.resizingEl.getBottom());
26298 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26305 * Orientation constant - Create a vertical SplitBar
26309 Roo.SplitBar.VERTICAL = 1;
26312 * Orientation constant - Create a horizontal SplitBar
26316 Roo.SplitBar.HORIZONTAL = 2;
26319 * Placement constant - The resizing element is to the left of the splitter element
26323 Roo.SplitBar.LEFT = 1;
26326 * Placement constant - The resizing element is to the right of the splitter element
26330 Roo.SplitBar.RIGHT = 2;
26333 * Placement constant - The resizing element is positioned above the splitter element
26337 Roo.SplitBar.TOP = 3;
26340 * Placement constant - The resizing element is positioned under splitter element
26344 Roo.SplitBar.BOTTOM = 4;
26347 * Ext JS Library 1.1.1
26348 * Copyright(c) 2006-2007, Ext JS, LLC.
26350 * Originally Released Under LGPL - original licence link has changed is not relivant.
26353 * <script type="text/javascript">
26358 * @extends Roo.util.Observable
26359 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26360 * This class also supports single and multi selection modes. <br>
26361 * Create a data model bound view:
26363 var store = new Roo.data.Store(...);
26365 var view = new Roo.View({
26367 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26369 singleSelect: true,
26370 selectedClass: "ydataview-selected",
26374 // listen for node click?
26375 view.on("click", function(vw, index, node, e){
26376 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26380 dataModel.load("foobar.xml");
26382 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26384 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26385 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26387 * Note: old style constructor is still suported (container, template, config)
26390 * Create a new View
26391 * @param {Object} config The config object
26394 Roo.View = function(config, depreciated_tpl, depreciated_config){
26396 this.parent = false;
26398 if (typeof(depreciated_tpl) == 'undefined') {
26399 // new way.. - universal constructor.
26400 Roo.apply(this, config);
26401 this.el = Roo.get(this.el);
26404 this.el = Roo.get(config);
26405 this.tpl = depreciated_tpl;
26406 Roo.apply(this, depreciated_config);
26408 this.wrapEl = this.el.wrap().wrap();
26409 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26412 if(typeof(this.tpl) == "string"){
26413 this.tpl = new Roo.Template(this.tpl);
26415 // support xtype ctors..
26416 this.tpl = new Roo.factory(this.tpl, Roo);
26420 this.tpl.compile();
26425 * @event beforeclick
26426 * Fires before a click is processed. Returns false to cancel the default action.
26427 * @param {Roo.View} this
26428 * @param {Number} index The index of the target node
26429 * @param {HTMLElement} node The target node
26430 * @param {Roo.EventObject} e The raw event object
26432 "beforeclick" : true,
26435 * Fires when a template node is clicked.
26436 * @param {Roo.View} this
26437 * @param {Number} index The index of the target node
26438 * @param {HTMLElement} node The target node
26439 * @param {Roo.EventObject} e The raw event object
26444 * Fires when a template node is double clicked.
26445 * @param {Roo.View} this
26446 * @param {Number} index The index of the target node
26447 * @param {HTMLElement} node The target node
26448 * @param {Roo.EventObject} e The raw event object
26452 * @event contextmenu
26453 * Fires when a template node is right clicked.
26454 * @param {Roo.View} this
26455 * @param {Number} index The index of the target node
26456 * @param {HTMLElement} node The target node
26457 * @param {Roo.EventObject} e The raw event object
26459 "contextmenu" : true,
26461 * @event selectionchange
26462 * Fires when the selected nodes change.
26463 * @param {Roo.View} this
26464 * @param {Array} selections Array of the selected nodes
26466 "selectionchange" : true,
26469 * @event beforeselect
26470 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26471 * @param {Roo.View} this
26472 * @param {HTMLElement} node The node to be selected
26473 * @param {Array} selections Array of currently selected nodes
26475 "beforeselect" : true,
26477 * @event preparedata
26478 * Fires on every row to render, to allow you to change the data.
26479 * @param {Roo.View} this
26480 * @param {Object} data to be rendered (change this)
26482 "preparedata" : true
26490 "click": this.onClick,
26491 "dblclick": this.onDblClick,
26492 "contextmenu": this.onContextMenu,
26496 this.selections = [];
26498 this.cmp = new Roo.CompositeElementLite([]);
26500 this.store = Roo.factory(this.store, Roo.data);
26501 this.setStore(this.store, true);
26504 if ( this.footer && this.footer.xtype) {
26506 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26508 this.footer.dataSource = this.store;
26509 this.footer.container = fctr;
26510 this.footer = Roo.factory(this.footer, Roo);
26511 fctr.insertFirst(this.el);
26513 // this is a bit insane - as the paging toolbar seems to detach the el..
26514 // dom.parentNode.parentNode.parentNode
26515 // they get detached?
26519 Roo.View.superclass.constructor.call(this);
26524 Roo.extend(Roo.View, Roo.util.Observable, {
26527 * @cfg {Roo.data.Store} store Data store to load data from.
26532 * @cfg {String|Roo.Element} el The container element.
26537 * @cfg {String|Roo.Template} tpl The template used by this View
26541 * @cfg {String} dataName the named area of the template to use as the data area
26542 * Works with domtemplates roo-name="name"
26546 * @cfg {String} selectedClass The css class to add to selected nodes
26548 selectedClass : "x-view-selected",
26550 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26555 * @cfg {String} text to display on mask (default Loading)
26559 * @cfg {Boolean} multiSelect Allow multiple selection
26561 multiSelect : false,
26563 * @cfg {Boolean} singleSelect Allow single selection
26565 singleSelect: false,
26568 * @cfg {Boolean} toggleSelect - selecting
26570 toggleSelect : false,
26573 * @cfg {Boolean} tickable - selecting
26578 * Returns the element this view is bound to.
26579 * @return {Roo.Element}
26581 getEl : function(){
26582 return this.wrapEl;
26588 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26590 refresh : function(){
26591 //Roo.log('refresh');
26594 // if we are using something like 'domtemplate', then
26595 // the what gets used is:
26596 // t.applySubtemplate(NAME, data, wrapping data..)
26597 // the outer template then get' applied with
26598 // the store 'extra data'
26599 // and the body get's added to the
26600 // roo-name="data" node?
26601 // <span class='roo-tpl-{name}'></span> ?????
26605 this.clearSelections();
26606 this.el.update("");
26608 var records = this.store.getRange();
26609 if(records.length < 1) {
26611 // is this valid?? = should it render a template??
26613 this.el.update(this.emptyText);
26617 if (this.dataName) {
26618 this.el.update(t.apply(this.store.meta)); //????
26619 el = this.el.child('.roo-tpl-' + this.dataName);
26622 for(var i = 0, len = records.length; i < len; i++){
26623 var data = this.prepareData(records[i].data, i, records[i]);
26624 this.fireEvent("preparedata", this, data, i, records[i]);
26626 var d = Roo.apply({}, data);
26629 Roo.apply(d, {'roo-id' : Roo.id()});
26633 Roo.each(this.parent.item, function(item){
26634 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26637 Roo.apply(d, {'roo-data-checked' : 'checked'});
26641 html[html.length] = Roo.util.Format.trim(
26643 t.applySubtemplate(this.dataName, d, this.store.meta) :
26650 el.update(html.join(""));
26651 this.nodes = el.dom.childNodes;
26652 this.updateIndexes(0);
26657 * Function to override to reformat the data that is sent to
26658 * the template for each node.
26659 * DEPRICATED - use the preparedata event handler.
26660 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26661 * a JSON object for an UpdateManager bound view).
26663 prepareData : function(data, index, record)
26665 this.fireEvent("preparedata", this, data, index, record);
26669 onUpdate : function(ds, record){
26670 // Roo.log('on update');
26671 this.clearSelections();
26672 var index = this.store.indexOf(record);
26673 var n = this.nodes[index];
26674 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26675 n.parentNode.removeChild(n);
26676 this.updateIndexes(index, index);
26682 onAdd : function(ds, records, index)
26684 //Roo.log(['on Add', ds, records, index] );
26685 this.clearSelections();
26686 if(this.nodes.length == 0){
26690 var n = this.nodes[index];
26691 for(var i = 0, len = records.length; i < len; i++){
26692 var d = this.prepareData(records[i].data, i, records[i]);
26694 this.tpl.insertBefore(n, d);
26697 this.tpl.append(this.el, d);
26700 this.updateIndexes(index);
26703 onRemove : function(ds, record, index){
26704 // Roo.log('onRemove');
26705 this.clearSelections();
26706 var el = this.dataName ?
26707 this.el.child('.roo-tpl-' + this.dataName) :
26710 el.dom.removeChild(this.nodes[index]);
26711 this.updateIndexes(index);
26715 * Refresh an individual node.
26716 * @param {Number} index
26718 refreshNode : function(index){
26719 this.onUpdate(this.store, this.store.getAt(index));
26722 updateIndexes : function(startIndex, endIndex){
26723 var ns = this.nodes;
26724 startIndex = startIndex || 0;
26725 endIndex = endIndex || ns.length - 1;
26726 for(var i = startIndex; i <= endIndex; i++){
26727 ns[i].nodeIndex = i;
26732 * Changes the data store this view uses and refresh the view.
26733 * @param {Store} store
26735 setStore : function(store, initial){
26736 if(!initial && this.store){
26737 this.store.un("datachanged", this.refresh);
26738 this.store.un("add", this.onAdd);
26739 this.store.un("remove", this.onRemove);
26740 this.store.un("update", this.onUpdate);
26741 this.store.un("clear", this.refresh);
26742 this.store.un("beforeload", this.onBeforeLoad);
26743 this.store.un("load", this.onLoad);
26744 this.store.un("loadexception", this.onLoad);
26748 store.on("datachanged", this.refresh, this);
26749 store.on("add", this.onAdd, this);
26750 store.on("remove", this.onRemove, this);
26751 store.on("update", this.onUpdate, this);
26752 store.on("clear", this.refresh, this);
26753 store.on("beforeload", this.onBeforeLoad, this);
26754 store.on("load", this.onLoad, this);
26755 store.on("loadexception", this.onLoad, this);
26763 * onbeforeLoad - masks the loading area.
26766 onBeforeLoad : function(store,opts)
26768 //Roo.log('onBeforeLoad');
26770 this.el.update("");
26772 this.el.mask(this.mask ? this.mask : "Loading" );
26774 onLoad : function ()
26781 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26782 * @param {HTMLElement} node
26783 * @return {HTMLElement} The template node
26785 findItemFromChild : function(node){
26786 var el = this.dataName ?
26787 this.el.child('.roo-tpl-' + this.dataName,true) :
26790 if(!node || node.parentNode == el){
26793 var p = node.parentNode;
26794 while(p && p != el){
26795 if(p.parentNode == el){
26804 onClick : function(e){
26805 var item = this.findItemFromChild(e.getTarget());
26807 var index = this.indexOf(item);
26808 if(this.onItemClick(item, index, e) !== false){
26809 this.fireEvent("click", this, index, item, e);
26812 this.clearSelections();
26817 onContextMenu : function(e){
26818 var item = this.findItemFromChild(e.getTarget());
26820 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26825 onDblClick : function(e){
26826 var item = this.findItemFromChild(e.getTarget());
26828 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26832 onItemClick : function(item, index, e)
26834 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26837 if (this.toggleSelect) {
26838 var m = this.isSelected(item) ? 'unselect' : 'select';
26841 _t[m](item, true, false);
26844 if(this.multiSelect || this.singleSelect){
26845 if(this.multiSelect && e.shiftKey && this.lastSelection){
26846 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26848 this.select(item, this.multiSelect && e.ctrlKey);
26849 this.lastSelection = item;
26852 if(!this.tickable){
26853 e.preventDefault();
26861 * Get the number of selected nodes.
26864 getSelectionCount : function(){
26865 return this.selections.length;
26869 * Get the currently selected nodes.
26870 * @return {Array} An array of HTMLElements
26872 getSelectedNodes : function(){
26873 return this.selections;
26877 * Get the indexes of the selected nodes.
26880 getSelectedIndexes : function(){
26881 var indexes = [], s = this.selections;
26882 for(var i = 0, len = s.length; i < len; i++){
26883 indexes.push(s[i].nodeIndex);
26889 * Clear all selections
26890 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26892 clearSelections : function(suppressEvent){
26893 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26894 this.cmp.elements = this.selections;
26895 this.cmp.removeClass(this.selectedClass);
26896 this.selections = [];
26897 if(!suppressEvent){
26898 this.fireEvent("selectionchange", this, this.selections);
26904 * Returns true if the passed node is selected
26905 * @param {HTMLElement/Number} node The node or node index
26906 * @return {Boolean}
26908 isSelected : function(node){
26909 var s = this.selections;
26913 node = this.getNode(node);
26914 return s.indexOf(node) !== -1;
26919 * @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
26920 * @param {Boolean} keepExisting (optional) true to keep existing selections
26921 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26923 select : function(nodeInfo, keepExisting, suppressEvent){
26924 if(nodeInfo instanceof Array){
26926 this.clearSelections(true);
26928 for(var i = 0, len = nodeInfo.length; i < len; i++){
26929 this.select(nodeInfo[i], true, true);
26933 var node = this.getNode(nodeInfo);
26934 if(!node || this.isSelected(node)){
26935 return; // already selected.
26938 this.clearSelections(true);
26941 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26942 Roo.fly(node).addClass(this.selectedClass);
26943 this.selections.push(node);
26944 if(!suppressEvent){
26945 this.fireEvent("selectionchange", this, this.selections);
26953 * @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
26954 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26955 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26957 unselect : function(nodeInfo, keepExisting, suppressEvent)
26959 if(nodeInfo instanceof Array){
26960 Roo.each(this.selections, function(s) {
26961 this.unselect(s, nodeInfo);
26965 var node = this.getNode(nodeInfo);
26966 if(!node || !this.isSelected(node)){
26967 //Roo.log("not selected");
26968 return; // not selected.
26972 Roo.each(this.selections, function(s) {
26974 Roo.fly(node).removeClass(this.selectedClass);
26981 this.selections= ns;
26982 this.fireEvent("selectionchange", this, this.selections);
26986 * Gets a template node.
26987 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26988 * @return {HTMLElement} The node or null if it wasn't found
26990 getNode : function(nodeInfo){
26991 if(typeof nodeInfo == "string"){
26992 return document.getElementById(nodeInfo);
26993 }else if(typeof nodeInfo == "number"){
26994 return this.nodes[nodeInfo];
27000 * Gets a range template nodes.
27001 * @param {Number} startIndex
27002 * @param {Number} endIndex
27003 * @return {Array} An array of nodes
27005 getNodes : function(start, end){
27006 var ns = this.nodes;
27007 start = start || 0;
27008 end = typeof end == "undefined" ? ns.length - 1 : end;
27011 for(var i = start; i <= end; i++){
27015 for(var i = start; i >= end; i--){
27023 * Finds the index of the passed node
27024 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27025 * @return {Number} The index of the node or -1
27027 indexOf : function(node){
27028 node = this.getNode(node);
27029 if(typeof node.nodeIndex == "number"){
27030 return node.nodeIndex;
27032 var ns = this.nodes;
27033 for(var i = 0, len = ns.length; i < len; i++){
27043 * Ext JS Library 1.1.1
27044 * Copyright(c) 2006-2007, Ext JS, LLC.
27046 * Originally Released Under LGPL - original licence link has changed is not relivant.
27049 * <script type="text/javascript">
27053 * @class Roo.JsonView
27054 * @extends Roo.View
27055 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27057 var view = new Roo.JsonView({
27058 container: "my-element",
27059 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27064 // listen for node click?
27065 view.on("click", function(vw, index, node, e){
27066 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27069 // direct load of JSON data
27070 view.load("foobar.php");
27072 // Example from my blog list
27073 var tpl = new Roo.Template(
27074 '<div class="entry">' +
27075 '<a class="entry-title" href="{link}">{title}</a>' +
27076 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27077 "</div><hr />"
27080 var moreView = new Roo.JsonView({
27081 container : "entry-list",
27085 moreView.on("beforerender", this.sortEntries, this);
27087 url: "/blog/get-posts.php",
27088 params: "allposts=true",
27089 text: "Loading Blog Entries..."
27093 * Note: old code is supported with arguments : (container, template, config)
27097 * Create a new JsonView
27099 * @param {Object} config The config object
27102 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27105 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27107 var um = this.el.getUpdateManager();
27108 um.setRenderer(this);
27109 um.on("update", this.onLoad, this);
27110 um.on("failure", this.onLoadException, this);
27113 * @event beforerender
27114 * Fires before rendering of the downloaded JSON data.
27115 * @param {Roo.JsonView} this
27116 * @param {Object} data The JSON data loaded
27120 * Fires when data is loaded.
27121 * @param {Roo.JsonView} this
27122 * @param {Object} data The JSON data loaded
27123 * @param {Object} response The raw Connect response object
27126 * @event loadexception
27127 * Fires when loading fails.
27128 * @param {Roo.JsonView} this
27129 * @param {Object} response The raw Connect response object
27132 'beforerender' : true,
27134 'loadexception' : true
27137 Roo.extend(Roo.JsonView, Roo.View, {
27139 * @type {String} The root property in the loaded JSON object that contains the data
27144 * Refreshes the view.
27146 refresh : function(){
27147 this.clearSelections();
27148 this.el.update("");
27150 var o = this.jsonData;
27151 if(o && o.length > 0){
27152 for(var i = 0, len = o.length; i < len; i++){
27153 var data = this.prepareData(o[i], i, o);
27154 html[html.length] = this.tpl.apply(data);
27157 html.push(this.emptyText);
27159 this.el.update(html.join(""));
27160 this.nodes = this.el.dom.childNodes;
27161 this.updateIndexes(0);
27165 * 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.
27166 * @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:
27169 url: "your-url.php",
27170 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27171 callback: yourFunction,
27172 scope: yourObject, //(optional scope)
27175 text: "Loading...",
27180 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27181 * 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.
27182 * @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}
27183 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27184 * @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.
27187 var um = this.el.getUpdateManager();
27188 um.update.apply(um, arguments);
27191 // note - render is a standard framework call...
27192 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27193 render : function(el, response){
27195 this.clearSelections();
27196 this.el.update("");
27199 if (response != '') {
27200 o = Roo.util.JSON.decode(response.responseText);
27203 o = o[this.jsonRoot];
27209 * The current JSON data or null
27212 this.beforeRender();
27217 * Get the number of records in the current JSON dataset
27220 getCount : function(){
27221 return this.jsonData ? this.jsonData.length : 0;
27225 * Returns the JSON object for the specified node(s)
27226 * @param {HTMLElement/Array} node The node or an array of nodes
27227 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27228 * you get the JSON object for the node
27230 getNodeData : function(node){
27231 if(node instanceof Array){
27233 for(var i = 0, len = node.length; i < len; i++){
27234 data.push(this.getNodeData(node[i]));
27238 return this.jsonData[this.indexOf(node)] || null;
27241 beforeRender : function(){
27242 this.snapshot = this.jsonData;
27244 this.sort.apply(this, this.sortInfo);
27246 this.fireEvent("beforerender", this, this.jsonData);
27249 onLoad : function(el, o){
27250 this.fireEvent("load", this, this.jsonData, o);
27253 onLoadException : function(el, o){
27254 this.fireEvent("loadexception", this, o);
27258 * Filter the data by a specific property.
27259 * @param {String} property A property on your JSON objects
27260 * @param {String/RegExp} value Either string that the property values
27261 * should start with, or a RegExp to test against the property
27263 filter : function(property, value){
27266 var ss = this.snapshot;
27267 if(typeof value == "string"){
27268 var vlen = value.length;
27270 this.clearFilter();
27273 value = value.toLowerCase();
27274 for(var i = 0, len = ss.length; i < len; i++){
27276 if(o[property].substr(0, vlen).toLowerCase() == value){
27280 } else if(value.exec){ // regex?
27281 for(var i = 0, len = ss.length; i < len; i++){
27283 if(value.test(o[property])){
27290 this.jsonData = data;
27296 * Filter by a function. The passed function will be called with each
27297 * object in the current dataset. If the function returns true the value is kept,
27298 * otherwise it is filtered.
27299 * @param {Function} fn
27300 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27302 filterBy : function(fn, scope){
27305 var ss = this.snapshot;
27306 for(var i = 0, len = ss.length; i < len; i++){
27308 if(fn.call(scope || this, o)){
27312 this.jsonData = data;
27318 * Clears the current filter.
27320 clearFilter : function(){
27321 if(this.snapshot && this.jsonData != this.snapshot){
27322 this.jsonData = this.snapshot;
27329 * Sorts the data for this view and refreshes it.
27330 * @param {String} property A property on your JSON objects to sort on
27331 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27332 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27334 sort : function(property, dir, sortType){
27335 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27338 var dsc = dir && dir.toLowerCase() == "desc";
27339 var f = function(o1, o2){
27340 var v1 = sortType ? sortType(o1[p]) : o1[p];
27341 var v2 = sortType ? sortType(o2[p]) : o2[p];
27344 return dsc ? +1 : -1;
27345 } else if(v1 > v2){
27346 return dsc ? -1 : +1;
27351 this.jsonData.sort(f);
27353 if(this.jsonData != this.snapshot){
27354 this.snapshot.sort(f);
27360 * Ext JS Library 1.1.1
27361 * Copyright(c) 2006-2007, Ext JS, LLC.
27363 * Originally Released Under LGPL - original licence link has changed is not relivant.
27366 * <script type="text/javascript">
27371 * @class Roo.ColorPalette
27372 * @extends Roo.Component
27373 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27374 * Here's an example of typical usage:
27376 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27377 cp.render('my-div');
27379 cp.on('select', function(palette, selColor){
27380 // do something with selColor
27384 * Create a new ColorPalette
27385 * @param {Object} config The config object
27387 Roo.ColorPalette = function(config){
27388 Roo.ColorPalette.superclass.constructor.call(this, config);
27392 * Fires when a color is selected
27393 * @param {ColorPalette} this
27394 * @param {String} color The 6-digit color hex code (without the # symbol)
27400 this.on("select", this.handler, this.scope, true);
27403 Roo.extend(Roo.ColorPalette, Roo.Component, {
27405 * @cfg {String} itemCls
27406 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27408 itemCls : "x-color-palette",
27410 * @cfg {String} value
27411 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27412 * the hex codes are case-sensitive.
27415 clickEvent:'click',
27417 ctype: "Roo.ColorPalette",
27420 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27422 allowReselect : false,
27425 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27426 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27427 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27428 * of colors with the width setting until the box is symmetrical.</p>
27429 * <p>You can override individual colors if needed:</p>
27431 var cp = new Roo.ColorPalette();
27432 cp.colors[0] = "FF0000"; // change the first box to red
27435 Or you can provide a custom array of your own for complete control:
27437 var cp = new Roo.ColorPalette();
27438 cp.colors = ["000000", "993300", "333300"];
27443 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27444 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27445 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27446 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27447 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27451 onRender : function(container, position){
27452 var t = new Roo.MasterTemplate(
27453 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27455 var c = this.colors;
27456 for(var i = 0, len = c.length; i < len; i++){
27459 var el = document.createElement("div");
27460 el.className = this.itemCls;
27462 container.dom.insertBefore(el, position);
27463 this.el = Roo.get(el);
27464 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27465 if(this.clickEvent != 'click'){
27466 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27471 afterRender : function(){
27472 Roo.ColorPalette.superclass.afterRender.call(this);
27474 var s = this.value;
27481 handleClick : function(e, t){
27482 e.preventDefault();
27483 if(!this.disabled){
27484 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27485 this.select(c.toUpperCase());
27490 * Selects the specified color in the palette (fires the select event)
27491 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27493 select : function(color){
27494 color = color.replace("#", "");
27495 if(color != this.value || this.allowReselect){
27498 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27500 el.child("a.color-"+color).addClass("x-color-palette-sel");
27501 this.value = color;
27502 this.fireEvent("select", this, color);
27507 * Ext JS Library 1.1.1
27508 * Copyright(c) 2006-2007, Ext JS, LLC.
27510 * Originally Released Under LGPL - original licence link has changed is not relivant.
27513 * <script type="text/javascript">
27517 * @class Roo.DatePicker
27518 * @extends Roo.Component
27519 * Simple date picker class.
27521 * Create a new DatePicker
27522 * @param {Object} config The config object
27524 Roo.DatePicker = function(config){
27525 Roo.DatePicker.superclass.constructor.call(this, config);
27527 this.value = config && config.value ?
27528 config.value.clearTime() : new Date().clearTime();
27533 * Fires when a date is selected
27534 * @param {DatePicker} this
27535 * @param {Date} date The selected date
27539 * @event monthchange
27540 * Fires when the displayed month changes
27541 * @param {DatePicker} this
27542 * @param {Date} date The selected month
27544 'monthchange': true
27548 this.on("select", this.handler, this.scope || this);
27550 // build the disabledDatesRE
27551 if(!this.disabledDatesRE && this.disabledDates){
27552 var dd = this.disabledDates;
27554 for(var i = 0; i < dd.length; i++){
27556 if(i != dd.length-1) {
27560 this.disabledDatesRE = new RegExp(re + ")");
27564 Roo.extend(Roo.DatePicker, Roo.Component, {
27566 * @cfg {String} todayText
27567 * The text to display on the button that selects the current date (defaults to "Today")
27569 todayText : "Today",
27571 * @cfg {String} okText
27572 * The text to display on the ok button
27574 okText : " OK ", //   to give the user extra clicking room
27576 * @cfg {String} cancelText
27577 * The text to display on the cancel button
27579 cancelText : "Cancel",
27581 * @cfg {String} todayTip
27582 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27584 todayTip : "{0} (Spacebar)",
27586 * @cfg {Date} minDate
27587 * Minimum allowable date (JavaScript date object, defaults to null)
27591 * @cfg {Date} maxDate
27592 * Maximum allowable date (JavaScript date object, defaults to null)
27596 * @cfg {String} minText
27597 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27599 minText : "This date is before the minimum date",
27601 * @cfg {String} maxText
27602 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27604 maxText : "This date is after the maximum date",
27606 * @cfg {String} format
27607 * The default date format string which can be overriden for localization support. The format must be
27608 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27612 * @cfg {Array} disabledDays
27613 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27615 disabledDays : null,
27617 * @cfg {String} disabledDaysText
27618 * The tooltip to display when the date falls on a disabled day (defaults to "")
27620 disabledDaysText : "",
27622 * @cfg {RegExp} disabledDatesRE
27623 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27625 disabledDatesRE : null,
27627 * @cfg {String} disabledDatesText
27628 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27630 disabledDatesText : "",
27632 * @cfg {Boolean} constrainToViewport
27633 * True to constrain the date picker to the viewport (defaults to true)
27635 constrainToViewport : true,
27637 * @cfg {Array} monthNames
27638 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27640 monthNames : Date.monthNames,
27642 * @cfg {Array} dayNames
27643 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27645 dayNames : Date.dayNames,
27647 * @cfg {String} nextText
27648 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27650 nextText: 'Next Month (Control+Right)',
27652 * @cfg {String} prevText
27653 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27655 prevText: 'Previous Month (Control+Left)',
27657 * @cfg {String} monthYearText
27658 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27660 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27662 * @cfg {Number} startDay
27663 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27667 * @cfg {Bool} showClear
27668 * Show a clear button (usefull for date form elements that can be blank.)
27674 * Sets the value of the date field
27675 * @param {Date} value The date to set
27677 setValue : function(value){
27678 var old = this.value;
27680 if (typeof(value) == 'string') {
27682 value = Date.parseDate(value, this.format);
27685 value = new Date();
27688 this.value = value.clearTime(true);
27690 this.update(this.value);
27695 * Gets the current selected value of the date field
27696 * @return {Date} The selected date
27698 getValue : function(){
27703 focus : function(){
27705 this.update(this.activeDate);
27710 onRender : function(container, position){
27713 '<table cellspacing="0">',
27714 '<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>',
27715 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27716 var dn = this.dayNames;
27717 for(var i = 0; i < 7; i++){
27718 var d = this.startDay+i;
27722 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27724 m[m.length] = "</tr></thead><tbody><tr>";
27725 for(var i = 0; i < 42; i++) {
27726 if(i % 7 == 0 && i != 0){
27727 m[m.length] = "</tr><tr>";
27729 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27731 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27732 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27734 var el = document.createElement("div");
27735 el.className = "x-date-picker";
27736 el.innerHTML = m.join("");
27738 container.dom.insertBefore(el, position);
27740 this.el = Roo.get(el);
27741 this.eventEl = Roo.get(el.firstChild);
27743 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27744 handler: this.showPrevMonth,
27746 preventDefault:true,
27750 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27751 handler: this.showNextMonth,
27753 preventDefault:true,
27757 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27759 this.monthPicker = this.el.down('div.x-date-mp');
27760 this.monthPicker.enableDisplayMode('block');
27762 var kn = new Roo.KeyNav(this.eventEl, {
27763 "left" : function(e){
27765 this.showPrevMonth() :
27766 this.update(this.activeDate.add("d", -1));
27769 "right" : function(e){
27771 this.showNextMonth() :
27772 this.update(this.activeDate.add("d", 1));
27775 "up" : function(e){
27777 this.showNextYear() :
27778 this.update(this.activeDate.add("d", -7));
27781 "down" : function(e){
27783 this.showPrevYear() :
27784 this.update(this.activeDate.add("d", 7));
27787 "pageUp" : function(e){
27788 this.showNextMonth();
27791 "pageDown" : function(e){
27792 this.showPrevMonth();
27795 "enter" : function(e){
27796 e.stopPropagation();
27803 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27805 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27807 this.el.unselectable();
27809 this.cells = this.el.select("table.x-date-inner tbody td");
27810 this.textNodes = this.el.query("table.x-date-inner tbody span");
27812 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27814 tooltip: this.monthYearText
27817 this.mbtn.on('click', this.showMonthPicker, this);
27818 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27821 var today = (new Date()).dateFormat(this.format);
27823 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27824 if (this.showClear) {
27825 baseTb.add( new Roo.Toolbar.Fill());
27828 text: String.format(this.todayText, today),
27829 tooltip: String.format(this.todayTip, today),
27830 handler: this.selectToday,
27834 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27837 if (this.showClear) {
27839 baseTb.add( new Roo.Toolbar.Fill());
27842 cls: 'x-btn-icon x-btn-clear',
27843 handler: function() {
27845 this.fireEvent("select", this, '');
27855 this.update(this.value);
27858 createMonthPicker : function(){
27859 if(!this.monthPicker.dom.firstChild){
27860 var buf = ['<table border="0" cellspacing="0">'];
27861 for(var i = 0; i < 6; i++){
27863 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27864 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27866 '<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>' :
27867 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27871 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27873 '</button><button type="button" class="x-date-mp-cancel">',
27875 '</button></td></tr>',
27878 this.monthPicker.update(buf.join(''));
27879 this.monthPicker.on('click', this.onMonthClick, this);
27880 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27882 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27883 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27885 this.mpMonths.each(function(m, a, i){
27888 m.dom.xmonth = 5 + Math.round(i * .5);
27890 m.dom.xmonth = Math.round((i-1) * .5);
27896 showMonthPicker : function(){
27897 this.createMonthPicker();
27898 var size = this.el.getSize();
27899 this.monthPicker.setSize(size);
27900 this.monthPicker.child('table').setSize(size);
27902 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27903 this.updateMPMonth(this.mpSelMonth);
27904 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27905 this.updateMPYear(this.mpSelYear);
27907 this.monthPicker.slideIn('t', {duration:.2});
27910 updateMPYear : function(y){
27912 var ys = this.mpYears.elements;
27913 for(var i = 1; i <= 10; i++){
27914 var td = ys[i-1], y2;
27916 y2 = y + Math.round(i * .5);
27917 td.firstChild.innerHTML = y2;
27920 y2 = y - (5-Math.round(i * .5));
27921 td.firstChild.innerHTML = y2;
27924 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27928 updateMPMonth : function(sm){
27929 this.mpMonths.each(function(m, a, i){
27930 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27934 selectMPMonth: function(m){
27938 onMonthClick : function(e, t){
27940 var el = new Roo.Element(t), pn;
27941 if(el.is('button.x-date-mp-cancel')){
27942 this.hideMonthPicker();
27944 else if(el.is('button.x-date-mp-ok')){
27945 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27946 this.hideMonthPicker();
27948 else if(pn = el.up('td.x-date-mp-month', 2)){
27949 this.mpMonths.removeClass('x-date-mp-sel');
27950 pn.addClass('x-date-mp-sel');
27951 this.mpSelMonth = pn.dom.xmonth;
27953 else if(pn = el.up('td.x-date-mp-year', 2)){
27954 this.mpYears.removeClass('x-date-mp-sel');
27955 pn.addClass('x-date-mp-sel');
27956 this.mpSelYear = pn.dom.xyear;
27958 else if(el.is('a.x-date-mp-prev')){
27959 this.updateMPYear(this.mpyear-10);
27961 else if(el.is('a.x-date-mp-next')){
27962 this.updateMPYear(this.mpyear+10);
27966 onMonthDblClick : function(e, t){
27968 var el = new Roo.Element(t), pn;
27969 if(pn = el.up('td.x-date-mp-month', 2)){
27970 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27971 this.hideMonthPicker();
27973 else if(pn = el.up('td.x-date-mp-year', 2)){
27974 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27975 this.hideMonthPicker();
27979 hideMonthPicker : function(disableAnim){
27980 if(this.monthPicker){
27981 if(disableAnim === true){
27982 this.monthPicker.hide();
27984 this.monthPicker.slideOut('t', {duration:.2});
27990 showPrevMonth : function(e){
27991 this.update(this.activeDate.add("mo", -1));
27995 showNextMonth : function(e){
27996 this.update(this.activeDate.add("mo", 1));
28000 showPrevYear : function(){
28001 this.update(this.activeDate.add("y", -1));
28005 showNextYear : function(){
28006 this.update(this.activeDate.add("y", 1));
28010 handleMouseWheel : function(e){
28011 var delta = e.getWheelDelta();
28013 this.showPrevMonth();
28015 } else if(delta < 0){
28016 this.showNextMonth();
28022 handleDateClick : function(e, t){
28024 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28025 this.setValue(new Date(t.dateValue));
28026 this.fireEvent("select", this, this.value);
28031 selectToday : function(){
28032 this.setValue(new Date().clearTime());
28033 this.fireEvent("select", this, this.value);
28037 update : function(date)
28039 var vd = this.activeDate;
28040 this.activeDate = date;
28042 var t = date.getTime();
28043 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28044 this.cells.removeClass("x-date-selected");
28045 this.cells.each(function(c){
28046 if(c.dom.firstChild.dateValue == t){
28047 c.addClass("x-date-selected");
28048 setTimeout(function(){
28049 try{c.dom.firstChild.focus();}catch(e){}
28058 var days = date.getDaysInMonth();
28059 var firstOfMonth = date.getFirstDateOfMonth();
28060 var startingPos = firstOfMonth.getDay()-this.startDay;
28062 if(startingPos <= this.startDay){
28066 var pm = date.add("mo", -1);
28067 var prevStart = pm.getDaysInMonth()-startingPos;
28069 var cells = this.cells.elements;
28070 var textEls = this.textNodes;
28071 days += startingPos;
28073 // convert everything to numbers so it's fast
28074 var day = 86400000;
28075 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28076 var today = new Date().clearTime().getTime();
28077 var sel = date.clearTime().getTime();
28078 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28079 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28080 var ddMatch = this.disabledDatesRE;
28081 var ddText = this.disabledDatesText;
28082 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28083 var ddaysText = this.disabledDaysText;
28084 var format = this.format;
28086 var setCellClass = function(cal, cell){
28088 var t = d.getTime();
28089 cell.firstChild.dateValue = t;
28091 cell.className += " x-date-today";
28092 cell.title = cal.todayText;
28095 cell.className += " x-date-selected";
28096 setTimeout(function(){
28097 try{cell.firstChild.focus();}catch(e){}
28102 cell.className = " x-date-disabled";
28103 cell.title = cal.minText;
28107 cell.className = " x-date-disabled";
28108 cell.title = cal.maxText;
28112 if(ddays.indexOf(d.getDay()) != -1){
28113 cell.title = ddaysText;
28114 cell.className = " x-date-disabled";
28117 if(ddMatch && format){
28118 var fvalue = d.dateFormat(format);
28119 if(ddMatch.test(fvalue)){
28120 cell.title = ddText.replace("%0", fvalue);
28121 cell.className = " x-date-disabled";
28127 for(; i < startingPos; i++) {
28128 textEls[i].innerHTML = (++prevStart);
28129 d.setDate(d.getDate()+1);
28130 cells[i].className = "x-date-prevday";
28131 setCellClass(this, cells[i]);
28133 for(; i < days; i++){
28134 intDay = i - startingPos + 1;
28135 textEls[i].innerHTML = (intDay);
28136 d.setDate(d.getDate()+1);
28137 cells[i].className = "x-date-active";
28138 setCellClass(this, cells[i]);
28141 for(; i < 42; i++) {
28142 textEls[i].innerHTML = (++extraDays);
28143 d.setDate(d.getDate()+1);
28144 cells[i].className = "x-date-nextday";
28145 setCellClass(this, cells[i]);
28148 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28149 this.fireEvent('monthchange', this, date);
28151 if(!this.internalRender){
28152 var main = this.el.dom.firstChild;
28153 var w = main.offsetWidth;
28154 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28155 Roo.fly(main).setWidth(w);
28156 this.internalRender = true;
28157 // opera does not respect the auto grow header center column
28158 // then, after it gets a width opera refuses to recalculate
28159 // without a second pass
28160 if(Roo.isOpera && !this.secondPass){
28161 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28162 this.secondPass = true;
28163 this.update.defer(10, this, [date]);
28171 * Ext JS Library 1.1.1
28172 * Copyright(c) 2006-2007, Ext JS, LLC.
28174 * Originally Released Under LGPL - original licence link has changed is not relivant.
28177 * <script type="text/javascript">
28180 * @class Roo.TabPanel
28181 * @extends Roo.util.Observable
28182 * A lightweight tab container.
28186 // basic tabs 1, built from existing content
28187 var tabs = new Roo.TabPanel("tabs1");
28188 tabs.addTab("script", "View Script");
28189 tabs.addTab("markup", "View Markup");
28190 tabs.activate("script");
28192 // more advanced tabs, built from javascript
28193 var jtabs = new Roo.TabPanel("jtabs");
28194 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28196 // set up the UpdateManager
28197 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28198 var updater = tab2.getUpdateManager();
28199 updater.setDefaultUrl("ajax1.htm");
28200 tab2.on('activate', updater.refresh, updater, true);
28202 // Use setUrl for Ajax loading
28203 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28204 tab3.setUrl("ajax2.htm", null, true);
28207 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28210 jtabs.activate("jtabs-1");
28213 * Create a new TabPanel.
28214 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28215 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28217 Roo.TabPanel = function(container, config){
28219 * The container element for this TabPanel.
28220 * @type Roo.Element
28222 this.el = Roo.get(container, true);
28224 if(typeof config == "boolean"){
28225 this.tabPosition = config ? "bottom" : "top";
28227 Roo.apply(this, config);
28230 if(this.tabPosition == "bottom"){
28231 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28232 this.el.addClass("x-tabs-bottom");
28234 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28235 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28236 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28238 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28240 if(this.tabPosition != "bottom"){
28241 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28242 * @type Roo.Element
28244 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28245 this.el.addClass("x-tabs-top");
28249 this.bodyEl.setStyle("position", "relative");
28251 this.active = null;
28252 this.activateDelegate = this.activate.createDelegate(this);
28257 * Fires when the active tab changes
28258 * @param {Roo.TabPanel} this
28259 * @param {Roo.TabPanelItem} activePanel The new active tab
28263 * @event beforetabchange
28264 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28265 * @param {Roo.TabPanel} this
28266 * @param {Object} e Set cancel to true on this object to cancel the tab change
28267 * @param {Roo.TabPanelItem} tab The tab being changed to
28269 "beforetabchange" : true
28272 Roo.EventManager.onWindowResize(this.onResize, this);
28273 this.cpad = this.el.getPadding("lr");
28274 this.hiddenCount = 0;
28277 // toolbar on the tabbar support...
28278 if (this.toolbar) {
28279 var tcfg = this.toolbar;
28280 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28281 this.toolbar = new Roo.Toolbar(tcfg);
28282 if (Roo.isSafari) {
28283 var tbl = tcfg.container.child('table', true);
28284 tbl.setAttribute('width', '100%');
28291 Roo.TabPanel.superclass.constructor.call(this);
28294 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28296 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28298 tabPosition : "top",
28300 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28302 currentTabWidth : 0,
28304 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28308 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28312 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28314 preferredTabWidth : 175,
28316 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28318 resizeTabs : false,
28320 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28322 monitorResize : true,
28324 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28329 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28330 * @param {String} id The id of the div to use <b>or create</b>
28331 * @param {String} text The text for the tab
28332 * @param {String} content (optional) Content to put in the TabPanelItem body
28333 * @param {Boolean} closable (optional) True to create a close icon on the tab
28334 * @return {Roo.TabPanelItem} The created TabPanelItem
28336 addTab : function(id, text, content, closable){
28337 var item = new Roo.TabPanelItem(this, id, text, closable);
28338 this.addTabItem(item);
28340 item.setContent(content);
28346 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28347 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28348 * @return {Roo.TabPanelItem}
28350 getTab : function(id){
28351 return this.items[id];
28355 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28356 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28358 hideTab : function(id){
28359 var t = this.items[id];
28362 this.hiddenCount++;
28363 this.autoSizeTabs();
28368 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28369 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28371 unhideTab : function(id){
28372 var t = this.items[id];
28374 t.setHidden(false);
28375 this.hiddenCount--;
28376 this.autoSizeTabs();
28381 * Adds an existing {@link Roo.TabPanelItem}.
28382 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28384 addTabItem : function(item){
28385 this.items[item.id] = item;
28386 this.items.push(item);
28387 if(this.resizeTabs){
28388 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28389 this.autoSizeTabs();
28396 * Removes a {@link Roo.TabPanelItem}.
28397 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28399 removeTab : function(id){
28400 var items = this.items;
28401 var tab = items[id];
28402 if(!tab) { return; }
28403 var index = items.indexOf(tab);
28404 if(this.active == tab && items.length > 1){
28405 var newTab = this.getNextAvailable(index);
28410 this.stripEl.dom.removeChild(tab.pnode.dom);
28411 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28412 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28414 items.splice(index, 1);
28415 delete this.items[tab.id];
28416 tab.fireEvent("close", tab);
28417 tab.purgeListeners();
28418 this.autoSizeTabs();
28421 getNextAvailable : function(start){
28422 var items = this.items;
28424 // look for a next tab that will slide over to
28425 // replace the one being removed
28426 while(index < items.length){
28427 var item = items[++index];
28428 if(item && !item.isHidden()){
28432 // if one isn't found select the previous tab (on the left)
28435 var item = items[--index];
28436 if(item && !item.isHidden()){
28444 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28445 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28447 disableTab : function(id){
28448 var tab = this.items[id];
28449 if(tab && this.active != tab){
28455 * Enables a {@link Roo.TabPanelItem} that is disabled.
28456 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28458 enableTab : function(id){
28459 var tab = this.items[id];
28464 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28465 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28466 * @return {Roo.TabPanelItem} The TabPanelItem.
28468 activate : function(id){
28469 var tab = this.items[id];
28473 if(tab == this.active || tab.disabled){
28477 this.fireEvent("beforetabchange", this, e, tab);
28478 if(e.cancel !== true && !tab.disabled){
28480 this.active.hide();
28482 this.active = this.items[id];
28483 this.active.show();
28484 this.fireEvent("tabchange", this, this.active);
28490 * Gets the active {@link Roo.TabPanelItem}.
28491 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28493 getActiveTab : function(){
28494 return this.active;
28498 * Updates the tab body element to fit the height of the container element
28499 * for overflow scrolling
28500 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28502 syncHeight : function(targetHeight){
28503 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28504 var bm = this.bodyEl.getMargins();
28505 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28506 this.bodyEl.setHeight(newHeight);
28510 onResize : function(){
28511 if(this.monitorResize){
28512 this.autoSizeTabs();
28517 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28519 beginUpdate : function(){
28520 this.updating = true;
28524 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28526 endUpdate : function(){
28527 this.updating = false;
28528 this.autoSizeTabs();
28532 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28534 autoSizeTabs : function(){
28535 var count = this.items.length;
28536 var vcount = count - this.hiddenCount;
28537 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28540 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28541 var availWidth = Math.floor(w / vcount);
28542 var b = this.stripBody;
28543 if(b.getWidth() > w){
28544 var tabs = this.items;
28545 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28546 if(availWidth < this.minTabWidth){
28547 /*if(!this.sleft){ // incomplete scrolling code
28548 this.createScrollButtons();
28551 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28554 if(this.currentTabWidth < this.preferredTabWidth){
28555 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28561 * Returns the number of tabs in this TabPanel.
28564 getCount : function(){
28565 return this.items.length;
28569 * Resizes all the tabs to the passed width
28570 * @param {Number} The new width
28572 setTabWidth : function(width){
28573 this.currentTabWidth = width;
28574 for(var i = 0, len = this.items.length; i < len; i++) {
28575 if(!this.items[i].isHidden()) {
28576 this.items[i].setWidth(width);
28582 * Destroys this TabPanel
28583 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28585 destroy : function(removeEl){
28586 Roo.EventManager.removeResizeListener(this.onResize, this);
28587 for(var i = 0, len = this.items.length; i < len; i++){
28588 this.items[i].purgeListeners();
28590 if(removeEl === true){
28591 this.el.update("");
28598 * @class Roo.TabPanelItem
28599 * @extends Roo.util.Observable
28600 * Represents an individual item (tab plus body) in a TabPanel.
28601 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28602 * @param {String} id The id of this TabPanelItem
28603 * @param {String} text The text for the tab of this TabPanelItem
28604 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28606 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28608 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28609 * @type Roo.TabPanel
28611 this.tabPanel = tabPanel;
28613 * The id for this TabPanelItem
28618 this.disabled = false;
28622 this.loaded = false;
28623 this.closable = closable;
28626 * The body element for this TabPanelItem.
28627 * @type Roo.Element
28629 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28630 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28631 this.bodyEl.setStyle("display", "block");
28632 this.bodyEl.setStyle("zoom", "1");
28635 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28637 this.el = Roo.get(els.el, true);
28638 this.inner = Roo.get(els.inner, true);
28639 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28640 this.pnode = Roo.get(els.el.parentNode, true);
28641 this.el.on("mousedown", this.onTabMouseDown, this);
28642 this.el.on("click", this.onTabClick, this);
28645 var c = Roo.get(els.close, true);
28646 c.dom.title = this.closeText;
28647 c.addClassOnOver("close-over");
28648 c.on("click", this.closeClick, this);
28654 * Fires when this tab becomes the active tab.
28655 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28656 * @param {Roo.TabPanelItem} this
28660 * @event beforeclose
28661 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28662 * @param {Roo.TabPanelItem} this
28663 * @param {Object} e Set cancel to true on this object to cancel the close.
28665 "beforeclose": true,
28668 * Fires when this tab is closed.
28669 * @param {Roo.TabPanelItem} this
28673 * @event deactivate
28674 * Fires when this tab is no longer the active tab.
28675 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28676 * @param {Roo.TabPanelItem} this
28678 "deactivate" : true
28680 this.hidden = false;
28682 Roo.TabPanelItem.superclass.constructor.call(this);
28685 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28686 purgeListeners : function(){
28687 Roo.util.Observable.prototype.purgeListeners.call(this);
28688 this.el.removeAllListeners();
28691 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28694 this.pnode.addClass("on");
28697 this.tabPanel.stripWrap.repaint();
28699 this.fireEvent("activate", this.tabPanel, this);
28703 * Returns true if this tab is the active tab.
28704 * @return {Boolean}
28706 isActive : function(){
28707 return this.tabPanel.getActiveTab() == this;
28711 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28714 this.pnode.removeClass("on");
28716 this.fireEvent("deactivate", this.tabPanel, this);
28719 hideAction : function(){
28720 this.bodyEl.hide();
28721 this.bodyEl.setStyle("position", "absolute");
28722 this.bodyEl.setLeft("-20000px");
28723 this.bodyEl.setTop("-20000px");
28726 showAction : function(){
28727 this.bodyEl.setStyle("position", "relative");
28728 this.bodyEl.setTop("");
28729 this.bodyEl.setLeft("");
28730 this.bodyEl.show();
28734 * Set the tooltip for the tab.
28735 * @param {String} tooltip The tab's tooltip
28737 setTooltip : function(text){
28738 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28739 this.textEl.dom.qtip = text;
28740 this.textEl.dom.removeAttribute('title');
28742 this.textEl.dom.title = text;
28746 onTabClick : function(e){
28747 e.preventDefault();
28748 this.tabPanel.activate(this.id);
28751 onTabMouseDown : function(e){
28752 e.preventDefault();
28753 this.tabPanel.activate(this.id);
28756 getWidth : function(){
28757 return this.inner.getWidth();
28760 setWidth : function(width){
28761 var iwidth = width - this.pnode.getPadding("lr");
28762 this.inner.setWidth(iwidth);
28763 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28764 this.pnode.setWidth(width);
28768 * Show or hide the tab
28769 * @param {Boolean} hidden True to hide or false to show.
28771 setHidden : function(hidden){
28772 this.hidden = hidden;
28773 this.pnode.setStyle("display", hidden ? "none" : "");
28777 * Returns true if this tab is "hidden"
28778 * @return {Boolean}
28780 isHidden : function(){
28781 return this.hidden;
28785 * Returns the text for this tab
28788 getText : function(){
28792 autoSize : function(){
28793 //this.el.beginMeasure();
28794 this.textEl.setWidth(1);
28796 * #2804 [new] Tabs in Roojs
28797 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28799 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28800 //this.el.endMeasure();
28804 * Sets the text for the tab (Note: this also sets the tooltip text)
28805 * @param {String} text The tab's text and tooltip
28807 setText : function(text){
28809 this.textEl.update(text);
28810 this.setTooltip(text);
28811 if(!this.tabPanel.resizeTabs){
28816 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28818 activate : function(){
28819 this.tabPanel.activate(this.id);
28823 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28825 disable : function(){
28826 if(this.tabPanel.active != this){
28827 this.disabled = true;
28828 this.pnode.addClass("disabled");
28833 * Enables this TabPanelItem if it was previously disabled.
28835 enable : function(){
28836 this.disabled = false;
28837 this.pnode.removeClass("disabled");
28841 * Sets the content for this TabPanelItem.
28842 * @param {String} content The content
28843 * @param {Boolean} loadScripts true to look for and load scripts
28845 setContent : function(content, loadScripts){
28846 this.bodyEl.update(content, loadScripts);
28850 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28851 * @return {Roo.UpdateManager} The UpdateManager
28853 getUpdateManager : function(){
28854 return this.bodyEl.getUpdateManager();
28858 * Set a URL to be used to load the content for this TabPanelItem.
28859 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28860 * @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)
28861 * @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)
28862 * @return {Roo.UpdateManager} The UpdateManager
28864 setUrl : function(url, params, loadOnce){
28865 if(this.refreshDelegate){
28866 this.un('activate', this.refreshDelegate);
28868 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28869 this.on("activate", this.refreshDelegate);
28870 return this.bodyEl.getUpdateManager();
28874 _handleRefresh : function(url, params, loadOnce){
28875 if(!loadOnce || !this.loaded){
28876 var updater = this.bodyEl.getUpdateManager();
28877 updater.update(url, params, this._setLoaded.createDelegate(this));
28882 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28883 * Will fail silently if the setUrl method has not been called.
28884 * This does not activate the panel, just updates its content.
28886 refresh : function(){
28887 if(this.refreshDelegate){
28888 this.loaded = false;
28889 this.refreshDelegate();
28894 _setLoaded : function(){
28895 this.loaded = true;
28899 closeClick : function(e){
28902 this.fireEvent("beforeclose", this, o);
28903 if(o.cancel !== true){
28904 this.tabPanel.removeTab(this.id);
28908 * The text displayed in the tooltip for the close icon.
28911 closeText : "Close this tab"
28915 Roo.TabPanel.prototype.createStrip = function(container){
28916 var strip = document.createElement("div");
28917 strip.className = "x-tabs-wrap";
28918 container.appendChild(strip);
28922 Roo.TabPanel.prototype.createStripList = function(strip){
28923 // div wrapper for retard IE
28924 // returns the "tr" element.
28925 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28926 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28927 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28928 return strip.firstChild.firstChild.firstChild.firstChild;
28931 Roo.TabPanel.prototype.createBody = function(container){
28932 var body = document.createElement("div");
28933 Roo.id(body, "tab-body");
28934 Roo.fly(body).addClass("x-tabs-body");
28935 container.appendChild(body);
28939 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28940 var body = Roo.getDom(id);
28942 body = document.createElement("div");
28945 Roo.fly(body).addClass("x-tabs-item-body");
28946 bodyEl.insertBefore(body, bodyEl.firstChild);
28950 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28951 var td = document.createElement("td");
28952 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28953 //stripEl.appendChild(td);
28955 td.className = "x-tabs-closable";
28956 if(!this.closeTpl){
28957 this.closeTpl = new Roo.Template(
28958 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28959 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28960 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28963 var el = this.closeTpl.overwrite(td, {"text": text});
28964 var close = el.getElementsByTagName("div")[0];
28965 var inner = el.getElementsByTagName("em")[0];
28966 return {"el": el, "close": close, "inner": inner};
28969 this.tabTpl = new Roo.Template(
28970 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28971 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28974 var el = this.tabTpl.overwrite(td, {"text": text});
28975 var inner = el.getElementsByTagName("em")[0];
28976 return {"el": el, "inner": inner};
28980 * Ext JS Library 1.1.1
28981 * Copyright(c) 2006-2007, Ext JS, LLC.
28983 * Originally Released Under LGPL - original licence link has changed is not relivant.
28986 * <script type="text/javascript">
28990 * @class Roo.Button
28991 * @extends Roo.util.Observable
28992 * Simple Button class
28993 * @cfg {String} text The button text
28994 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
28995 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
28996 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
28997 * @cfg {Object} scope The scope of the handler
28998 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
28999 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29000 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29001 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29002 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29003 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29004 applies if enableToggle = true)
29005 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29006 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29007 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29009 * Create a new button
29010 * @param {Object} config The config object
29012 Roo.Button = function(renderTo, config)
29016 renderTo = config.renderTo || false;
29019 Roo.apply(this, config);
29023 * Fires when this button is clicked
29024 * @param {Button} this
29025 * @param {EventObject} e The click event
29030 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29031 * @param {Button} this
29032 * @param {Boolean} pressed
29037 * Fires when the mouse hovers over the button
29038 * @param {Button} this
29039 * @param {Event} e The event object
29041 'mouseover' : true,
29044 * Fires when the mouse exits the button
29045 * @param {Button} this
29046 * @param {Event} e The event object
29051 * Fires when the button is rendered
29052 * @param {Button} this
29057 this.menu = Roo.menu.MenuMgr.get(this.menu);
29059 // register listeners first!! - so render can be captured..
29060 Roo.util.Observable.call(this);
29062 this.render(renderTo);
29068 Roo.extend(Roo.Button, Roo.util.Observable, {
29074 * Read-only. True if this button is hidden
29079 * Read-only. True if this button is disabled
29084 * Read-only. True if this button is pressed (only if enableToggle = true)
29090 * @cfg {Number} tabIndex
29091 * The DOM tabIndex for this button (defaults to undefined)
29093 tabIndex : undefined,
29096 * @cfg {Boolean} enableToggle
29097 * True to enable pressed/not pressed toggling (defaults to false)
29099 enableToggle: false,
29101 * @cfg {Mixed} menu
29102 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29106 * @cfg {String} menuAlign
29107 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29109 menuAlign : "tl-bl?",
29112 * @cfg {String} iconCls
29113 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29115 iconCls : undefined,
29117 * @cfg {String} type
29118 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29123 menuClassTarget: 'tr',
29126 * @cfg {String} clickEvent
29127 * The type of event to map to the button's event handler (defaults to 'click')
29129 clickEvent : 'click',
29132 * @cfg {Boolean} handleMouseEvents
29133 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29135 handleMouseEvents : true,
29138 * @cfg {String} tooltipType
29139 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29141 tooltipType : 'qtip',
29144 * @cfg {String} cls
29145 * A CSS class to apply to the button's main element.
29149 * @cfg {Roo.Template} template (Optional)
29150 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29151 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29152 * require code modifications if required elements (e.g. a button) aren't present.
29156 render : function(renderTo){
29158 if(this.hideParent){
29159 this.parentEl = Roo.get(renderTo);
29161 if(!this.dhconfig){
29162 if(!this.template){
29163 if(!Roo.Button.buttonTemplate){
29164 // hideous table template
29165 Roo.Button.buttonTemplate = new Roo.Template(
29166 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29167 '<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>',
29168 "</tr></tbody></table>");
29170 this.template = Roo.Button.buttonTemplate;
29172 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29173 var btnEl = btn.child("button:first");
29174 btnEl.on('focus', this.onFocus, this);
29175 btnEl.on('blur', this.onBlur, this);
29177 btn.addClass(this.cls);
29180 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29183 btnEl.addClass(this.iconCls);
29185 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29188 if(this.tabIndex !== undefined){
29189 btnEl.dom.tabIndex = this.tabIndex;
29192 if(typeof this.tooltip == 'object'){
29193 Roo.QuickTips.tips(Roo.apply({
29197 btnEl.dom[this.tooltipType] = this.tooltip;
29201 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29205 this.el.dom.id = this.el.id = this.id;
29208 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29209 this.menu.on("show", this.onMenuShow, this);
29210 this.menu.on("hide", this.onMenuHide, this);
29212 btn.addClass("x-btn");
29213 if(Roo.isIE && !Roo.isIE7){
29214 this.autoWidth.defer(1, this);
29218 if(this.handleMouseEvents){
29219 btn.on("mouseover", this.onMouseOver, this);
29220 btn.on("mouseout", this.onMouseOut, this);
29221 btn.on("mousedown", this.onMouseDown, this);
29223 btn.on(this.clickEvent, this.onClick, this);
29224 //btn.on("mouseup", this.onMouseUp, this);
29231 Roo.ButtonToggleMgr.register(this);
29233 this.el.addClass("x-btn-pressed");
29236 var repeater = new Roo.util.ClickRepeater(btn,
29237 typeof this.repeat == "object" ? this.repeat : {}
29239 repeater.on("click", this.onClick, this);
29242 this.fireEvent('render', this);
29246 * Returns the button's underlying element
29247 * @return {Roo.Element} The element
29249 getEl : function(){
29254 * Destroys this Button and removes any listeners.
29256 destroy : function(){
29257 Roo.ButtonToggleMgr.unregister(this);
29258 this.el.removeAllListeners();
29259 this.purgeListeners();
29264 autoWidth : function(){
29266 this.el.setWidth("auto");
29267 if(Roo.isIE7 && Roo.isStrict){
29268 var ib = this.el.child('button');
29269 if(ib && ib.getWidth() > 20){
29271 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29276 this.el.beginMeasure();
29278 if(this.el.getWidth() < this.minWidth){
29279 this.el.setWidth(this.minWidth);
29282 this.el.endMeasure();
29289 * Assigns this button's click handler
29290 * @param {Function} handler The function to call when the button is clicked
29291 * @param {Object} scope (optional) Scope for the function passed in
29293 setHandler : function(handler, scope){
29294 this.handler = handler;
29295 this.scope = scope;
29299 * Sets this button's text
29300 * @param {String} text The button text
29302 setText : function(text){
29305 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29311 * Gets the text for this button
29312 * @return {String} The button text
29314 getText : function(){
29322 this.hidden = false;
29324 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29332 this.hidden = true;
29334 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29339 * Convenience function for boolean show/hide
29340 * @param {Boolean} visible True to show, false to hide
29342 setVisible: function(visible){
29351 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29352 * @param {Boolean} state (optional) Force a particular state
29354 toggle : function(state){
29355 state = state === undefined ? !this.pressed : state;
29356 if(state != this.pressed){
29358 this.el.addClass("x-btn-pressed");
29359 this.pressed = true;
29360 this.fireEvent("toggle", this, true);
29362 this.el.removeClass("x-btn-pressed");
29363 this.pressed = false;
29364 this.fireEvent("toggle", this, false);
29366 if(this.toggleHandler){
29367 this.toggleHandler.call(this.scope || this, this, state);
29375 focus : function(){
29376 this.el.child('button:first').focus();
29380 * Disable this button
29382 disable : function(){
29384 this.el.addClass("x-btn-disabled");
29386 this.disabled = true;
29390 * Enable this button
29392 enable : function(){
29394 this.el.removeClass("x-btn-disabled");
29396 this.disabled = false;
29400 * Convenience function for boolean enable/disable
29401 * @param {Boolean} enabled True to enable, false to disable
29403 setDisabled : function(v){
29404 this[v !== true ? "enable" : "disable"]();
29408 onClick : function(e)
29411 e.preventDefault();
29416 if(!this.disabled){
29417 if(this.enableToggle){
29420 if(this.menu && !this.menu.isVisible()){
29421 this.menu.show(this.el, this.menuAlign);
29423 this.fireEvent("click", this, e);
29425 this.el.removeClass("x-btn-over");
29426 this.handler.call(this.scope || this, this, e);
29431 onMouseOver : function(e){
29432 if(!this.disabled){
29433 this.el.addClass("x-btn-over");
29434 this.fireEvent('mouseover', this, e);
29438 onMouseOut : function(e){
29439 if(!e.within(this.el, true)){
29440 this.el.removeClass("x-btn-over");
29441 this.fireEvent('mouseout', this, e);
29445 onFocus : function(e){
29446 if(!this.disabled){
29447 this.el.addClass("x-btn-focus");
29451 onBlur : function(e){
29452 this.el.removeClass("x-btn-focus");
29455 onMouseDown : function(e){
29456 if(!this.disabled && e.button == 0){
29457 this.el.addClass("x-btn-click");
29458 Roo.get(document).on('mouseup', this.onMouseUp, this);
29462 onMouseUp : function(e){
29464 this.el.removeClass("x-btn-click");
29465 Roo.get(document).un('mouseup', this.onMouseUp, this);
29469 onMenuShow : function(e){
29470 this.el.addClass("x-btn-menu-active");
29473 onMenuHide : function(e){
29474 this.el.removeClass("x-btn-menu-active");
29478 // Private utility class used by Button
29479 Roo.ButtonToggleMgr = function(){
29482 function toggleGroup(btn, state){
29484 var g = groups[btn.toggleGroup];
29485 for(var i = 0, l = g.length; i < l; i++){
29487 g[i].toggle(false);
29494 register : function(btn){
29495 if(!btn.toggleGroup){
29498 var g = groups[btn.toggleGroup];
29500 g = groups[btn.toggleGroup] = [];
29503 btn.on("toggle", toggleGroup);
29506 unregister : function(btn){
29507 if(!btn.toggleGroup){
29510 var g = groups[btn.toggleGroup];
29513 btn.un("toggle", toggleGroup);
29519 * Ext JS Library 1.1.1
29520 * Copyright(c) 2006-2007, Ext JS, LLC.
29522 * Originally Released Under LGPL - original licence link has changed is not relivant.
29525 * <script type="text/javascript">
29529 * @class Roo.SplitButton
29530 * @extends Roo.Button
29531 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29532 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29533 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29534 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29535 * @cfg {String} arrowTooltip The title attribute of the arrow
29537 * Create a new menu button
29538 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29539 * @param {Object} config The config object
29541 Roo.SplitButton = function(renderTo, config){
29542 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29544 * @event arrowclick
29545 * Fires when this button's arrow is clicked
29546 * @param {SplitButton} this
29547 * @param {EventObject} e The click event
29549 this.addEvents({"arrowclick":true});
29552 Roo.extend(Roo.SplitButton, Roo.Button, {
29553 render : function(renderTo){
29554 // this is one sweet looking template!
29555 var tpl = new Roo.Template(
29556 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29557 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29558 '<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>',
29559 "</tbody></table></td><td>",
29560 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29561 '<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>',
29562 "</tbody></table></td></tr></table>"
29564 var btn = tpl.append(renderTo, [this.text, this.type], true);
29565 var btnEl = btn.child("button");
29567 btn.addClass(this.cls);
29570 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29573 btnEl.addClass(this.iconCls);
29575 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29579 if(this.handleMouseEvents){
29580 btn.on("mouseover", this.onMouseOver, this);
29581 btn.on("mouseout", this.onMouseOut, this);
29582 btn.on("mousedown", this.onMouseDown, this);
29583 btn.on("mouseup", this.onMouseUp, this);
29585 btn.on(this.clickEvent, this.onClick, this);
29587 if(typeof this.tooltip == 'object'){
29588 Roo.QuickTips.tips(Roo.apply({
29592 btnEl.dom[this.tooltipType] = this.tooltip;
29595 if(this.arrowTooltip){
29596 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29605 this.el.addClass("x-btn-pressed");
29607 if(Roo.isIE && !Roo.isIE7){
29608 this.autoWidth.defer(1, this);
29613 this.menu.on("show", this.onMenuShow, this);
29614 this.menu.on("hide", this.onMenuHide, this);
29616 this.fireEvent('render', this);
29620 autoWidth : function(){
29622 var tbl = this.el.child("table:first");
29623 var tbl2 = this.el.child("table:last");
29624 this.el.setWidth("auto");
29625 tbl.setWidth("auto");
29626 if(Roo.isIE7 && Roo.isStrict){
29627 var ib = this.el.child('button:first');
29628 if(ib && ib.getWidth() > 20){
29630 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29635 this.el.beginMeasure();
29637 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29638 tbl.setWidth(this.minWidth-tbl2.getWidth());
29641 this.el.endMeasure();
29644 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29648 * Sets this button's click handler
29649 * @param {Function} handler The function to call when the button is clicked
29650 * @param {Object} scope (optional) Scope for the function passed above
29652 setHandler : function(handler, scope){
29653 this.handler = handler;
29654 this.scope = scope;
29658 * Sets this button's arrow click handler
29659 * @param {Function} handler The function to call when the arrow is clicked
29660 * @param {Object} scope (optional) Scope for the function passed above
29662 setArrowHandler : function(handler, scope){
29663 this.arrowHandler = handler;
29664 this.scope = scope;
29670 focus : function(){
29672 this.el.child("button:first").focus();
29677 onClick : function(e){
29678 e.preventDefault();
29679 if(!this.disabled){
29680 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29681 if(this.menu && !this.menu.isVisible()){
29682 this.menu.show(this.el, this.menuAlign);
29684 this.fireEvent("arrowclick", this, e);
29685 if(this.arrowHandler){
29686 this.arrowHandler.call(this.scope || this, this, e);
29689 this.fireEvent("click", this, e);
29691 this.handler.call(this.scope || this, this, e);
29697 onMouseDown : function(e){
29698 if(!this.disabled){
29699 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29703 onMouseUp : function(e){
29704 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29709 // backwards compat
29710 Roo.MenuButton = Roo.SplitButton;/*
29712 * Ext JS Library 1.1.1
29713 * Copyright(c) 2006-2007, Ext JS, LLC.
29715 * Originally Released Under LGPL - original licence link has changed is not relivant.
29718 * <script type="text/javascript">
29722 * @class Roo.Toolbar
29723 * Basic Toolbar class.
29725 * Creates a new Toolbar
29726 * @param {Object} container The config object
29728 Roo.Toolbar = function(container, buttons, config)
29730 /// old consturctor format still supported..
29731 if(container instanceof Array){ // omit the container for later rendering
29732 buttons = container;
29736 if (typeof(container) == 'object' && container.xtype) {
29737 config = container;
29738 container = config.container;
29739 buttons = config.buttons || []; // not really - use items!!
29742 if (config && config.items) {
29743 xitems = config.items;
29744 delete config.items;
29746 Roo.apply(this, config);
29747 this.buttons = buttons;
29750 this.render(container);
29752 this.xitems = xitems;
29753 Roo.each(xitems, function(b) {
29759 Roo.Toolbar.prototype = {
29761 * @cfg {Array} items
29762 * array of button configs or elements to add (will be converted to a MixedCollection)
29766 * @cfg {String/HTMLElement/Element} container
29767 * The id or element that will contain the toolbar
29770 render : function(ct){
29771 this.el = Roo.get(ct);
29773 this.el.addClass(this.cls);
29775 // using a table allows for vertical alignment
29776 // 100% width is needed by Safari...
29777 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29778 this.tr = this.el.child("tr", true);
29780 this.items = new Roo.util.MixedCollection(false, function(o){
29781 return o.id || ("item" + (++autoId));
29784 this.add.apply(this, this.buttons);
29785 delete this.buttons;
29790 * Adds element(s) to the toolbar -- this function takes a variable number of
29791 * arguments of mixed type and adds them to the toolbar.
29792 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29794 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29795 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29796 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29797 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29798 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29799 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29800 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29801 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29802 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29804 * @param {Mixed} arg2
29805 * @param {Mixed} etc.
29808 var a = arguments, l = a.length;
29809 for(var i = 0; i < l; i++){
29814 _add : function(el) {
29817 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29820 if (el.applyTo){ // some kind of form field
29821 return this.addField(el);
29823 if (el.render){ // some kind of Toolbar.Item
29824 return this.addItem(el);
29826 if (typeof el == "string"){ // string
29827 if(el == "separator" || el == "-"){
29828 return this.addSeparator();
29831 return this.addSpacer();
29834 return this.addFill();
29836 return this.addText(el);
29839 if(el.tagName){ // element
29840 return this.addElement(el);
29842 if(typeof el == "object"){ // must be button config?
29843 return this.addButton(el);
29845 // and now what?!?!
29851 * Add an Xtype element
29852 * @param {Object} xtype Xtype Object
29853 * @return {Object} created Object
29855 addxtype : function(e){
29856 return this.add(e);
29860 * Returns the Element for this toolbar.
29861 * @return {Roo.Element}
29863 getEl : function(){
29869 * @return {Roo.Toolbar.Item} The separator item
29871 addSeparator : function(){
29872 return this.addItem(new Roo.Toolbar.Separator());
29876 * Adds a spacer element
29877 * @return {Roo.Toolbar.Spacer} The spacer item
29879 addSpacer : function(){
29880 return this.addItem(new Roo.Toolbar.Spacer());
29884 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29885 * @return {Roo.Toolbar.Fill} The fill item
29887 addFill : function(){
29888 return this.addItem(new Roo.Toolbar.Fill());
29892 * Adds any standard HTML element to the toolbar
29893 * @param {String/HTMLElement/Element} el The element or id of the element to add
29894 * @return {Roo.Toolbar.Item} The element's item
29896 addElement : function(el){
29897 return this.addItem(new Roo.Toolbar.Item(el));
29900 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29901 * @type Roo.util.MixedCollection
29906 * Adds any Toolbar.Item or subclass
29907 * @param {Roo.Toolbar.Item} item
29908 * @return {Roo.Toolbar.Item} The item
29910 addItem : function(item){
29911 var td = this.nextBlock();
29913 this.items.add(item);
29918 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29919 * @param {Object/Array} config A button config or array of configs
29920 * @return {Roo.Toolbar.Button/Array}
29922 addButton : function(config){
29923 if(config instanceof Array){
29925 for(var i = 0, len = config.length; i < len; i++) {
29926 buttons.push(this.addButton(config[i]));
29931 if(!(config instanceof Roo.Toolbar.Button)){
29933 new Roo.Toolbar.SplitButton(config) :
29934 new Roo.Toolbar.Button(config);
29936 var td = this.nextBlock();
29943 * Adds text to the toolbar
29944 * @param {String} text The text to add
29945 * @return {Roo.Toolbar.Item} The element's item
29947 addText : function(text){
29948 return this.addItem(new Roo.Toolbar.TextItem(text));
29952 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29953 * @param {Number} index The index where the item is to be inserted
29954 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29955 * @return {Roo.Toolbar.Button/Item}
29957 insertButton : function(index, item){
29958 if(item instanceof Array){
29960 for(var i = 0, len = item.length; i < len; i++) {
29961 buttons.push(this.insertButton(index + i, item[i]));
29965 if (!(item instanceof Roo.Toolbar.Button)){
29966 item = new Roo.Toolbar.Button(item);
29968 var td = document.createElement("td");
29969 this.tr.insertBefore(td, this.tr.childNodes[index]);
29971 this.items.insert(index, item);
29976 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29977 * @param {Object} config
29978 * @return {Roo.Toolbar.Item} The element's item
29980 addDom : function(config, returnEl){
29981 var td = this.nextBlock();
29982 Roo.DomHelper.overwrite(td, config);
29983 var ti = new Roo.Toolbar.Item(td.firstChild);
29985 this.items.add(ti);
29990 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29991 * @type Roo.util.MixedCollection
29996 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
29997 * Note: the field should not have been rendered yet. For a field that has already been
29998 * rendered, use {@link #addElement}.
29999 * @param {Roo.form.Field} field
30000 * @return {Roo.ToolbarItem}
30004 addField : function(field) {
30005 if (!this.fields) {
30007 this.fields = new Roo.util.MixedCollection(false, function(o){
30008 return o.id || ("item" + (++autoId));
30013 var td = this.nextBlock();
30015 var ti = new Roo.Toolbar.Item(td.firstChild);
30017 this.items.add(ti);
30018 this.fields.add(field);
30029 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30030 this.el.child('div').hide();
30038 this.el.child('div').show();
30042 nextBlock : function(){
30043 var td = document.createElement("td");
30044 this.tr.appendChild(td);
30049 destroy : function(){
30050 if(this.items){ // rendered?
30051 Roo.destroy.apply(Roo, this.items.items);
30053 if(this.fields){ // rendered?
30054 Roo.destroy.apply(Roo, this.fields.items);
30056 Roo.Element.uncache(this.el, this.tr);
30061 * @class Roo.Toolbar.Item
30062 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30064 * Creates a new Item
30065 * @param {HTMLElement} el
30067 Roo.Toolbar.Item = function(el){
30069 if (typeof (el.xtype) != 'undefined') {
30074 this.el = Roo.getDom(el);
30075 this.id = Roo.id(this.el);
30076 this.hidden = false;
30081 * Fires when the button is rendered
30082 * @param {Button} this
30086 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30088 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30089 //Roo.Toolbar.Item.prototype = {
30092 * Get this item's HTML Element
30093 * @return {HTMLElement}
30095 getEl : function(){
30100 render : function(td){
30103 td.appendChild(this.el);
30105 this.fireEvent('render', this);
30109 * Removes and destroys this item.
30111 destroy : function(){
30112 this.td.parentNode.removeChild(this.td);
30119 this.hidden = false;
30120 this.td.style.display = "";
30127 this.hidden = true;
30128 this.td.style.display = "none";
30132 * Convenience function for boolean show/hide.
30133 * @param {Boolean} visible true to show/false to hide
30135 setVisible: function(visible){
30144 * Try to focus this item.
30146 focus : function(){
30147 Roo.fly(this.el).focus();
30151 * Disables this item.
30153 disable : function(){
30154 Roo.fly(this.td).addClass("x-item-disabled");
30155 this.disabled = true;
30156 this.el.disabled = true;
30160 * Enables this item.
30162 enable : function(){
30163 Roo.fly(this.td).removeClass("x-item-disabled");
30164 this.disabled = false;
30165 this.el.disabled = false;
30171 * @class Roo.Toolbar.Separator
30172 * @extends Roo.Toolbar.Item
30173 * A simple toolbar separator class
30175 * Creates a new Separator
30177 Roo.Toolbar.Separator = function(cfg){
30179 var s = document.createElement("span");
30180 s.className = "ytb-sep";
30185 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30187 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30188 enable:Roo.emptyFn,
30189 disable:Roo.emptyFn,
30194 * @class Roo.Toolbar.Spacer
30195 * @extends Roo.Toolbar.Item
30196 * A simple element that adds extra horizontal space to a toolbar.
30198 * Creates a new Spacer
30200 Roo.Toolbar.Spacer = function(cfg){
30201 var s = document.createElement("div");
30202 s.className = "ytb-spacer";
30206 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30208 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30209 enable:Roo.emptyFn,
30210 disable:Roo.emptyFn,
30215 * @class Roo.Toolbar.Fill
30216 * @extends Roo.Toolbar.Spacer
30217 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30219 * Creates a new Spacer
30221 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30223 render : function(td){
30224 td.style.width = '100%';
30225 Roo.Toolbar.Fill.superclass.render.call(this, td);
30230 * @class Roo.Toolbar.TextItem
30231 * @extends Roo.Toolbar.Item
30232 * A simple class that renders text directly into a toolbar.
30234 * Creates a new TextItem
30235 * @param {String} text
30237 Roo.Toolbar.TextItem = function(cfg){
30238 var text = cfg || "";
30239 if (typeof(cfg) == 'object') {
30240 text = cfg.text || "";
30244 var s = document.createElement("span");
30245 s.className = "ytb-text";
30246 s.innerHTML = text;
30251 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30253 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30256 enable:Roo.emptyFn,
30257 disable:Roo.emptyFn,
30262 * @class Roo.Toolbar.Button
30263 * @extends Roo.Button
30264 * A button that renders into a toolbar.
30266 * Creates a new Button
30267 * @param {Object} config A standard {@link Roo.Button} config object
30269 Roo.Toolbar.Button = function(config){
30270 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30272 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30273 render : function(td){
30275 Roo.Toolbar.Button.superclass.render.call(this, td);
30279 * Removes and destroys this button
30281 destroy : function(){
30282 Roo.Toolbar.Button.superclass.destroy.call(this);
30283 this.td.parentNode.removeChild(this.td);
30287 * Shows this button
30290 this.hidden = false;
30291 this.td.style.display = "";
30295 * Hides this button
30298 this.hidden = true;
30299 this.td.style.display = "none";
30303 * Disables this item
30305 disable : function(){
30306 Roo.fly(this.td).addClass("x-item-disabled");
30307 this.disabled = true;
30311 * Enables this item
30313 enable : function(){
30314 Roo.fly(this.td).removeClass("x-item-disabled");
30315 this.disabled = false;
30318 // backwards compat
30319 Roo.ToolbarButton = Roo.Toolbar.Button;
30322 * @class Roo.Toolbar.SplitButton
30323 * @extends Roo.SplitButton
30324 * A menu button that renders into a toolbar.
30326 * Creates a new SplitButton
30327 * @param {Object} config A standard {@link Roo.SplitButton} config object
30329 Roo.Toolbar.SplitButton = function(config){
30330 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30332 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30333 render : function(td){
30335 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30339 * Removes and destroys this button
30341 destroy : function(){
30342 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30343 this.td.parentNode.removeChild(this.td);
30347 * Shows this button
30350 this.hidden = false;
30351 this.td.style.display = "";
30355 * Hides this button
30358 this.hidden = true;
30359 this.td.style.display = "none";
30363 // backwards compat
30364 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30366 * Ext JS Library 1.1.1
30367 * Copyright(c) 2006-2007, Ext JS, LLC.
30369 * Originally Released Under LGPL - original licence link has changed is not relivant.
30372 * <script type="text/javascript">
30376 * @class Roo.PagingToolbar
30377 * @extends Roo.Toolbar
30378 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30380 * Create a new PagingToolbar
30381 * @param {Object} config The config object
30383 Roo.PagingToolbar = function(el, ds, config)
30385 // old args format still supported... - xtype is prefered..
30386 if (typeof(el) == 'object' && el.xtype) {
30387 // created from xtype...
30389 ds = el.dataSource;
30390 el = config.container;
30393 if (config.items) {
30394 items = config.items;
30398 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30401 this.renderButtons(this.el);
30404 // supprot items array.
30406 Roo.each(items, function(e) {
30407 this.add(Roo.factory(e));
30412 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30414 * @cfg {Roo.data.Store} dataSource
30415 * The underlying data store providing the paged data
30418 * @cfg {String/HTMLElement/Element} container
30419 * container The id or element that will contain the toolbar
30422 * @cfg {Boolean} displayInfo
30423 * True to display the displayMsg (defaults to false)
30426 * @cfg {Number} pageSize
30427 * The number of records to display per page (defaults to 20)
30431 * @cfg {String} displayMsg
30432 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30434 displayMsg : 'Displaying {0} - {1} of {2}',
30436 * @cfg {String} emptyMsg
30437 * The message to display when no records are found (defaults to "No data to display")
30439 emptyMsg : 'No data to display',
30441 * Customizable piece of the default paging text (defaults to "Page")
30444 beforePageText : "Page",
30446 * Customizable piece of the default paging text (defaults to "of %0")
30449 afterPageText : "of {0}",
30451 * Customizable piece of the default paging text (defaults to "First Page")
30454 firstText : "First Page",
30456 * Customizable piece of the default paging text (defaults to "Previous Page")
30459 prevText : "Previous Page",
30461 * Customizable piece of the default paging text (defaults to "Next Page")
30464 nextText : "Next Page",
30466 * Customizable piece of the default paging text (defaults to "Last Page")
30469 lastText : "Last Page",
30471 * Customizable piece of the default paging text (defaults to "Refresh")
30474 refreshText : "Refresh",
30477 renderButtons : function(el){
30478 Roo.PagingToolbar.superclass.render.call(this, el);
30479 this.first = this.addButton({
30480 tooltip: this.firstText,
30481 cls: "x-btn-icon x-grid-page-first",
30483 handler: this.onClick.createDelegate(this, ["first"])
30485 this.prev = this.addButton({
30486 tooltip: this.prevText,
30487 cls: "x-btn-icon x-grid-page-prev",
30489 handler: this.onClick.createDelegate(this, ["prev"])
30491 //this.addSeparator();
30492 this.add(this.beforePageText);
30493 this.field = Roo.get(this.addDom({
30498 cls: "x-grid-page-number"
30500 this.field.on("keydown", this.onPagingKeydown, this);
30501 this.field.on("focus", function(){this.dom.select();});
30502 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30503 this.field.setHeight(18);
30504 //this.addSeparator();
30505 this.next = this.addButton({
30506 tooltip: this.nextText,
30507 cls: "x-btn-icon x-grid-page-next",
30509 handler: this.onClick.createDelegate(this, ["next"])
30511 this.last = this.addButton({
30512 tooltip: this.lastText,
30513 cls: "x-btn-icon x-grid-page-last",
30515 handler: this.onClick.createDelegate(this, ["last"])
30517 //this.addSeparator();
30518 this.loading = this.addButton({
30519 tooltip: this.refreshText,
30520 cls: "x-btn-icon x-grid-loading",
30521 handler: this.onClick.createDelegate(this, ["refresh"])
30524 if(this.displayInfo){
30525 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30530 updateInfo : function(){
30531 if(this.displayEl){
30532 var count = this.ds.getCount();
30533 var msg = count == 0 ?
30537 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30539 this.displayEl.update(msg);
30544 onLoad : function(ds, r, o){
30545 this.cursor = o.params ? o.params.start : 0;
30546 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30548 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30549 this.field.dom.value = ap;
30550 this.first.setDisabled(ap == 1);
30551 this.prev.setDisabled(ap == 1);
30552 this.next.setDisabled(ap == ps);
30553 this.last.setDisabled(ap == ps);
30554 this.loading.enable();
30559 getPageData : function(){
30560 var total = this.ds.getTotalCount();
30563 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30564 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30569 onLoadError : function(){
30570 this.loading.enable();
30574 onPagingKeydown : function(e){
30575 var k = e.getKey();
30576 var d = this.getPageData();
30578 var v = this.field.dom.value, pageNum;
30579 if(!v || isNaN(pageNum = parseInt(v, 10))){
30580 this.field.dom.value = d.activePage;
30583 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30584 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30587 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))
30589 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30590 this.field.dom.value = pageNum;
30591 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30594 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30596 var v = this.field.dom.value, pageNum;
30597 var increment = (e.shiftKey) ? 10 : 1;
30598 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30601 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30602 this.field.dom.value = d.activePage;
30605 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30607 this.field.dom.value = parseInt(v, 10) + increment;
30608 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30609 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30616 beforeLoad : function(){
30618 this.loading.disable();
30623 onClick : function(which){
30627 ds.load({params:{start: 0, limit: this.pageSize}});
30630 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30633 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30636 var total = ds.getTotalCount();
30637 var extra = total % this.pageSize;
30638 var lastStart = extra ? (total - extra) : total-this.pageSize;
30639 ds.load({params:{start: lastStart, limit: this.pageSize}});
30642 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30648 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30649 * @param {Roo.data.Store} store The data store to unbind
30651 unbind : function(ds){
30652 ds.un("beforeload", this.beforeLoad, this);
30653 ds.un("load", this.onLoad, this);
30654 ds.un("loadexception", this.onLoadError, this);
30655 ds.un("remove", this.updateInfo, this);
30656 ds.un("add", this.updateInfo, this);
30657 this.ds = undefined;
30661 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30662 * @param {Roo.data.Store} store The data store to bind
30664 bind : function(ds){
30665 ds.on("beforeload", this.beforeLoad, this);
30666 ds.on("load", this.onLoad, this);
30667 ds.on("loadexception", this.onLoadError, this);
30668 ds.on("remove", this.updateInfo, this);
30669 ds.on("add", this.updateInfo, this);
30674 * Ext JS Library 1.1.1
30675 * Copyright(c) 2006-2007, Ext JS, LLC.
30677 * Originally Released Under LGPL - original licence link has changed is not relivant.
30680 * <script type="text/javascript">
30684 * @class Roo.Resizable
30685 * @extends Roo.util.Observable
30686 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30687 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30688 * 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
30689 * the element will be wrapped for you automatically.</p>
30690 * <p>Here is the list of valid resize handles:</p>
30693 ------ -------------------
30702 'hd' horizontal drag
30705 * <p>Here's an example showing the creation of a typical Resizable:</p>
30707 var resizer = new Roo.Resizable("element-id", {
30715 resizer.on("resize", myHandler);
30717 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30718 * resizer.east.setDisplayed(false);</p>
30719 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30720 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30721 * resize operation's new size (defaults to [0, 0])
30722 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30723 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30724 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30725 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30726 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30727 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30728 * @cfg {Number} width The width of the element in pixels (defaults to null)
30729 * @cfg {Number} height The height of the element in pixels (defaults to null)
30730 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30731 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30732 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30733 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30734 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30735 * in favor of the handles config option (defaults to false)
30736 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30737 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30738 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30739 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30740 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30741 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30742 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30743 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30744 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30745 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30746 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30748 * Create a new resizable component
30749 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30750 * @param {Object} config configuration options
30752 Roo.Resizable = function(el, config)
30754 this.el = Roo.get(el);
30756 if(config && config.wrap){
30757 config.resizeChild = this.el;
30758 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30759 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30760 this.el.setStyle("overflow", "hidden");
30761 this.el.setPositioning(config.resizeChild.getPositioning());
30762 config.resizeChild.clearPositioning();
30763 if(!config.width || !config.height){
30764 var csize = config.resizeChild.getSize();
30765 this.el.setSize(csize.width, csize.height);
30767 if(config.pinned && !config.adjustments){
30768 config.adjustments = "auto";
30772 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30773 this.proxy.unselectable();
30774 this.proxy.enableDisplayMode('block');
30776 Roo.apply(this, config);
30779 this.disableTrackOver = true;
30780 this.el.addClass("x-resizable-pinned");
30782 // if the element isn't positioned, make it relative
30783 var position = this.el.getStyle("position");
30784 if(position != "absolute" && position != "fixed"){
30785 this.el.setStyle("position", "relative");
30787 if(!this.handles){ // no handles passed, must be legacy style
30788 this.handles = 's,e,se';
30789 if(this.multiDirectional){
30790 this.handles += ',n,w';
30793 if(this.handles == "all"){
30794 this.handles = "n s e w ne nw se sw";
30796 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30797 var ps = Roo.Resizable.positions;
30798 for(var i = 0, len = hs.length; i < len; i++){
30799 if(hs[i] && ps[hs[i]]){
30800 var pos = ps[hs[i]];
30801 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30805 this.corner = this.southeast;
30807 // updateBox = the box can move..
30808 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30809 this.updateBox = true;
30812 this.activeHandle = null;
30814 if(this.resizeChild){
30815 if(typeof this.resizeChild == "boolean"){
30816 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30818 this.resizeChild = Roo.get(this.resizeChild, true);
30822 if(this.adjustments == "auto"){
30823 var rc = this.resizeChild;
30824 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30825 if(rc && (hw || hn)){
30826 rc.position("relative");
30827 rc.setLeft(hw ? hw.el.getWidth() : 0);
30828 rc.setTop(hn ? hn.el.getHeight() : 0);
30830 this.adjustments = [
30831 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30832 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30836 if(this.draggable){
30837 this.dd = this.dynamic ?
30838 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30839 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30845 * @event beforeresize
30846 * Fired before resize is allowed. Set enabled to false to cancel resize.
30847 * @param {Roo.Resizable} this
30848 * @param {Roo.EventObject} e The mousedown event
30850 "beforeresize" : true,
30853 * Fired a resizing.
30854 * @param {Roo.Resizable} this
30855 * @param {Number} x The new x position
30856 * @param {Number} y The new y position
30857 * @param {Number} w The new w width
30858 * @param {Number} h The new h hight
30859 * @param {Roo.EventObject} e The mouseup event
30864 * Fired after a resize.
30865 * @param {Roo.Resizable} this
30866 * @param {Number} width The new width
30867 * @param {Number} height The new height
30868 * @param {Roo.EventObject} e The mouseup event
30873 if(this.width !== null && this.height !== null){
30874 this.resizeTo(this.width, this.height);
30876 this.updateChildSize();
30879 this.el.dom.style.zoom = 1;
30881 Roo.Resizable.superclass.constructor.call(this);
30884 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30885 resizeChild : false,
30886 adjustments : [0, 0],
30896 multiDirectional : false,
30897 disableTrackOver : false,
30898 easing : 'easeOutStrong',
30899 widthIncrement : 0,
30900 heightIncrement : 0,
30904 preserveRatio : false,
30905 transparent: false,
30911 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30913 constrainTo: undefined,
30915 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30917 resizeRegion: undefined,
30921 * Perform a manual resize
30922 * @param {Number} width
30923 * @param {Number} height
30925 resizeTo : function(width, height){
30926 this.el.setSize(width, height);
30927 this.updateChildSize();
30928 this.fireEvent("resize", this, width, height, null);
30932 startSizing : function(e, handle){
30933 this.fireEvent("beforeresize", this, e);
30934 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30937 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30938 this.overlay.unselectable();
30939 this.overlay.enableDisplayMode("block");
30940 this.overlay.on("mousemove", this.onMouseMove, this);
30941 this.overlay.on("mouseup", this.onMouseUp, this);
30943 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30945 this.resizing = true;
30946 this.startBox = this.el.getBox();
30947 this.startPoint = e.getXY();
30948 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30949 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30951 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30952 this.overlay.show();
30954 if(this.constrainTo) {
30955 var ct = Roo.get(this.constrainTo);
30956 this.resizeRegion = ct.getRegion().adjust(
30957 ct.getFrameWidth('t'),
30958 ct.getFrameWidth('l'),
30959 -ct.getFrameWidth('b'),
30960 -ct.getFrameWidth('r')
30964 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30966 this.proxy.setBox(this.startBox);
30968 this.proxy.setStyle('visibility', 'visible');
30974 onMouseDown : function(handle, e){
30977 this.activeHandle = handle;
30978 this.startSizing(e, handle);
30983 onMouseUp : function(e){
30984 var size = this.resizeElement();
30985 this.resizing = false;
30987 this.overlay.hide();
30989 this.fireEvent("resize", this, size.width, size.height, e);
30993 updateChildSize : function(){
30995 if(this.resizeChild){
30997 var child = this.resizeChild;
30998 var adj = this.adjustments;
30999 if(el.dom.offsetWidth){
31000 var b = el.getSize(true);
31001 child.setSize(b.width+adj[0], b.height+adj[1]);
31003 // Second call here for IE
31004 // The first call enables instant resizing and
31005 // the second call corrects scroll bars if they
31008 setTimeout(function(){
31009 if(el.dom.offsetWidth){
31010 var b = el.getSize(true);
31011 child.setSize(b.width+adj[0], b.height+adj[1]);
31019 snap : function(value, inc, min){
31020 if(!inc || !value) {
31023 var newValue = value;
31024 var m = value % inc;
31027 newValue = value + (inc-m);
31029 newValue = value - m;
31032 return Math.max(min, newValue);
31036 resizeElement : function(){
31037 var box = this.proxy.getBox();
31038 if(this.updateBox){
31039 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31041 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31043 this.updateChildSize();
31051 constrain : function(v, diff, m, mx){
31054 }else if(v - diff > mx){
31061 onMouseMove : function(e){
31064 try{// try catch so if something goes wrong the user doesn't get hung
31066 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31070 //var curXY = this.startPoint;
31071 var curSize = this.curSize || this.startBox;
31072 var x = this.startBox.x, y = this.startBox.y;
31073 var ox = x, oy = y;
31074 var w = curSize.width, h = curSize.height;
31075 var ow = w, oh = h;
31076 var mw = this.minWidth, mh = this.minHeight;
31077 var mxw = this.maxWidth, mxh = this.maxHeight;
31078 var wi = this.widthIncrement;
31079 var hi = this.heightIncrement;
31081 var eventXY = e.getXY();
31082 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31083 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31085 var pos = this.activeHandle.position;
31090 w = Math.min(Math.max(mw, w), mxw);
31095 h = Math.min(Math.max(mh, h), mxh);
31100 w = Math.min(Math.max(mw, w), mxw);
31101 h = Math.min(Math.max(mh, h), mxh);
31104 diffY = this.constrain(h, diffY, mh, mxh);
31111 var adiffX = Math.abs(diffX);
31112 var sub = (adiffX % wi); // how much
31113 if (sub > (wi/2)) { // far enough to snap
31114 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31116 // remove difference..
31117 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31121 x = Math.max(this.minX, x);
31124 diffX = this.constrain(w, diffX, mw, mxw);
31130 w = Math.min(Math.max(mw, w), mxw);
31131 diffY = this.constrain(h, diffY, mh, mxh);
31136 diffX = this.constrain(w, diffX, mw, mxw);
31137 diffY = this.constrain(h, diffY, mh, mxh);
31144 diffX = this.constrain(w, diffX, mw, mxw);
31146 h = Math.min(Math.max(mh, h), mxh);
31152 var sw = this.snap(w, wi, mw);
31153 var sh = this.snap(h, hi, mh);
31154 if(sw != w || sh != h){
31177 if(this.preserveRatio){
31182 h = Math.min(Math.max(mh, h), mxh);
31187 w = Math.min(Math.max(mw, w), mxw);
31192 w = Math.min(Math.max(mw, w), mxw);
31198 w = Math.min(Math.max(mw, w), mxw);
31204 h = Math.min(Math.max(mh, h), mxh);
31212 h = Math.min(Math.max(mh, h), mxh);
31222 h = Math.min(Math.max(mh, h), mxh);
31230 if (pos == 'hdrag') {
31233 this.proxy.setBounds(x, y, w, h);
31235 this.resizeElement();
31239 this.fireEvent("resizing", this, x, y, w, h, e);
31243 handleOver : function(){
31245 this.el.addClass("x-resizable-over");
31250 handleOut : function(){
31251 if(!this.resizing){
31252 this.el.removeClass("x-resizable-over");
31257 * Returns the element this component is bound to.
31258 * @return {Roo.Element}
31260 getEl : function(){
31265 * Returns the resizeChild element (or null).
31266 * @return {Roo.Element}
31268 getResizeChild : function(){
31269 return this.resizeChild;
31271 groupHandler : function()
31276 * Destroys this resizable. If the element was wrapped and
31277 * removeEl is not true then the element remains.
31278 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31280 destroy : function(removeEl){
31281 this.proxy.remove();
31283 this.overlay.removeAllListeners();
31284 this.overlay.remove();
31286 var ps = Roo.Resizable.positions;
31288 if(typeof ps[k] != "function" && this[ps[k]]){
31289 var h = this[ps[k]];
31290 h.el.removeAllListeners();
31295 this.el.update("");
31302 // hash to map config positions to true positions
31303 Roo.Resizable.positions = {
31304 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31309 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31311 // only initialize the template if resizable is used
31312 var tpl = Roo.DomHelper.createTemplate(
31313 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31316 Roo.Resizable.Handle.prototype.tpl = tpl;
31318 this.position = pos;
31320 // show north drag fro topdra
31321 var handlepos = pos == 'hdrag' ? 'north' : pos;
31323 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31324 if (pos == 'hdrag') {
31325 this.el.setStyle('cursor', 'pointer');
31327 this.el.unselectable();
31329 this.el.setOpacity(0);
31331 this.el.on("mousedown", this.onMouseDown, this);
31332 if(!disableTrackOver){
31333 this.el.on("mouseover", this.onMouseOver, this);
31334 this.el.on("mouseout", this.onMouseOut, this);
31339 Roo.Resizable.Handle.prototype = {
31340 afterResize : function(rz){
31345 onMouseDown : function(e){
31346 this.rz.onMouseDown(this, e);
31349 onMouseOver : function(e){
31350 this.rz.handleOver(this, e);
31353 onMouseOut : function(e){
31354 this.rz.handleOut(this, e);
31358 * Ext JS Library 1.1.1
31359 * Copyright(c) 2006-2007, Ext JS, LLC.
31361 * Originally Released Under LGPL - original licence link has changed is not relivant.
31364 * <script type="text/javascript">
31368 * @class Roo.Editor
31369 * @extends Roo.Component
31370 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31372 * Create a new Editor
31373 * @param {Roo.form.Field} field The Field object (or descendant)
31374 * @param {Object} config The config object
31376 Roo.Editor = function(field, config){
31377 Roo.Editor.superclass.constructor.call(this, config);
31378 this.field = field;
31381 * @event beforestartedit
31382 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31383 * false from the handler of this event.
31384 * @param {Editor} this
31385 * @param {Roo.Element} boundEl The underlying element bound to this editor
31386 * @param {Mixed} value The field value being set
31388 "beforestartedit" : true,
31391 * Fires when this editor is displayed
31392 * @param {Roo.Element} boundEl The underlying element bound to this editor
31393 * @param {Mixed} value The starting field value
31395 "startedit" : true,
31397 * @event beforecomplete
31398 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31399 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31400 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31401 * event will not fire since no edit actually occurred.
31402 * @param {Editor} this
31403 * @param {Mixed} value The current field value
31404 * @param {Mixed} startValue The original field value
31406 "beforecomplete" : true,
31409 * Fires after editing is complete and any changed value has been written to the underlying field.
31410 * @param {Editor} this
31411 * @param {Mixed} value The current field value
31412 * @param {Mixed} startValue The original field value
31416 * @event specialkey
31417 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31418 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31419 * @param {Roo.form.Field} this
31420 * @param {Roo.EventObject} e The event object
31422 "specialkey" : true
31426 Roo.extend(Roo.Editor, Roo.Component, {
31428 * @cfg {Boolean/String} autosize
31429 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31430 * or "height" to adopt the height only (defaults to false)
31433 * @cfg {Boolean} revertInvalid
31434 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31435 * validation fails (defaults to true)
31438 * @cfg {Boolean} ignoreNoChange
31439 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31440 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31441 * will never be ignored.
31444 * @cfg {Boolean} hideEl
31445 * False to keep the bound element visible while the editor is displayed (defaults to true)
31448 * @cfg {Mixed} value
31449 * The data value of the underlying field (defaults to "")
31453 * @cfg {String} alignment
31454 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31458 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31459 * for bottom-right shadow (defaults to "frame")
31463 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31467 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31469 completeOnEnter : false,
31471 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31473 cancelOnEsc : false,
31475 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31480 onRender : function(ct, position){
31481 this.el = new Roo.Layer({
31482 shadow: this.shadow,
31488 constrain: this.constrain
31490 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31491 if(this.field.msgTarget != 'title'){
31492 this.field.msgTarget = 'qtip';
31494 this.field.render(this.el);
31496 this.field.el.dom.setAttribute('autocomplete', 'off');
31498 this.field.on("specialkey", this.onSpecialKey, this);
31499 if(this.swallowKeys){
31500 this.field.el.swallowEvent(['keydown','keypress']);
31503 this.field.on("blur", this.onBlur, this);
31504 if(this.field.grow){
31505 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31509 onSpecialKey : function(field, e)
31511 //Roo.log('editor onSpecialKey');
31512 if(this.completeOnEnter && e.getKey() == e.ENTER){
31514 this.completeEdit();
31517 // do not fire special key otherwise it might hide close the editor...
31518 if(e.getKey() == e.ENTER){
31521 if(this.cancelOnEsc && e.getKey() == e.ESC){
31525 this.fireEvent('specialkey', field, e);
31530 * Starts the editing process and shows the editor.
31531 * @param {String/HTMLElement/Element} el The element to edit
31532 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31533 * to the innerHTML of el.
31535 startEdit : function(el, value){
31537 this.completeEdit();
31539 this.boundEl = Roo.get(el);
31540 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31541 if(!this.rendered){
31542 this.render(this.parentEl || document.body);
31544 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31547 this.startValue = v;
31548 this.field.setValue(v);
31550 var sz = this.boundEl.getSize();
31551 switch(this.autoSize){
31553 this.setSize(sz.width, "");
31556 this.setSize("", sz.height);
31559 this.setSize(sz.width, sz.height);
31562 this.el.alignTo(this.boundEl, this.alignment);
31563 this.editing = true;
31565 Roo.QuickTips.disable();
31571 * Sets the height and width of this editor.
31572 * @param {Number} width The new width
31573 * @param {Number} height The new height
31575 setSize : function(w, h){
31576 this.field.setSize(w, h);
31583 * Realigns the editor to the bound field based on the current alignment config value.
31585 realign : function(){
31586 this.el.alignTo(this.boundEl, this.alignment);
31590 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31591 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31593 completeEdit : function(remainVisible){
31597 var v = this.getValue();
31598 if(this.revertInvalid !== false && !this.field.isValid()){
31599 v = this.startValue;
31600 this.cancelEdit(true);
31602 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31603 this.editing = false;
31607 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31608 this.editing = false;
31609 if(this.updateEl && this.boundEl){
31610 this.boundEl.update(v);
31612 if(remainVisible !== true){
31615 this.fireEvent("complete", this, v, this.startValue);
31620 onShow : function(){
31622 if(this.hideEl !== false){
31623 this.boundEl.hide();
31626 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31627 this.fixIEFocus = true;
31628 this.deferredFocus.defer(50, this);
31630 this.field.focus();
31632 this.fireEvent("startedit", this.boundEl, this.startValue);
31635 deferredFocus : function(){
31637 this.field.focus();
31642 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31643 * reverted to the original starting value.
31644 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31645 * cancel (defaults to false)
31647 cancelEdit : function(remainVisible){
31649 this.setValue(this.startValue);
31650 if(remainVisible !== true){
31657 onBlur : function(){
31658 if(this.allowBlur !== true && this.editing){
31659 this.completeEdit();
31664 onHide : function(){
31666 this.completeEdit();
31670 if(this.field.collapse){
31671 this.field.collapse();
31674 if(this.hideEl !== false){
31675 this.boundEl.show();
31678 Roo.QuickTips.enable();
31683 * Sets the data value of the editor
31684 * @param {Mixed} value Any valid value supported by the underlying field
31686 setValue : function(v){
31687 this.field.setValue(v);
31691 * Gets the data value of the editor
31692 * @return {Mixed} The data value
31694 getValue : function(){
31695 return this.field.getValue();
31699 * Ext JS Library 1.1.1
31700 * Copyright(c) 2006-2007, Ext JS, LLC.
31702 * Originally Released Under LGPL - original licence link has changed is not relivant.
31705 * <script type="text/javascript">
31709 * @class Roo.BasicDialog
31710 * @extends Roo.util.Observable
31711 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31713 var dlg = new Roo.BasicDialog("my-dlg", {
31722 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31723 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31724 dlg.addButton('Cancel', dlg.hide, dlg);
31727 <b>A Dialog should always be a direct child of the body element.</b>
31728 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31729 * @cfg {String} title Default text to display in the title bar (defaults to null)
31730 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31731 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31732 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31733 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31734 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31735 * (defaults to null with no animation)
31736 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31737 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31738 * property for valid values (defaults to 'all')
31739 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31740 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31741 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31742 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31743 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31744 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31745 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31746 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31747 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31748 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31749 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31750 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31751 * draggable = true (defaults to false)
31752 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31753 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31754 * shadow (defaults to false)
31755 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31756 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31757 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31758 * @cfg {Array} buttons Array of buttons
31759 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31761 * Create a new BasicDialog.
31762 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31763 * @param {Object} config Configuration options
31765 Roo.BasicDialog = function(el, config){
31766 this.el = Roo.get(el);
31767 var dh = Roo.DomHelper;
31768 if(!this.el && config && config.autoCreate){
31769 if(typeof config.autoCreate == "object"){
31770 if(!config.autoCreate.id){
31771 config.autoCreate.id = el;
31773 this.el = dh.append(document.body,
31774 config.autoCreate, true);
31776 this.el = dh.append(document.body,
31777 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31781 el.setDisplayed(true);
31782 el.hide = this.hideAction;
31784 el.addClass("x-dlg");
31786 Roo.apply(this, config);
31788 this.proxy = el.createProxy("x-dlg-proxy");
31789 this.proxy.hide = this.hideAction;
31790 this.proxy.setOpacity(.5);
31794 el.setWidth(config.width);
31797 el.setHeight(config.height);
31799 this.size = el.getSize();
31800 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31801 this.xy = [config.x,config.y];
31803 this.xy = el.getCenterXY(true);
31805 /** The header element @type Roo.Element */
31806 this.header = el.child("> .x-dlg-hd");
31807 /** The body element @type Roo.Element */
31808 this.body = el.child("> .x-dlg-bd");
31809 /** The footer element @type Roo.Element */
31810 this.footer = el.child("> .x-dlg-ft");
31813 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31816 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31819 this.header.unselectable();
31821 this.header.update(this.title);
31823 // this element allows the dialog to be focused for keyboard event
31824 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31825 this.focusEl.swallowEvent("click", true);
31827 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31829 // wrap the body and footer for special rendering
31830 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31832 this.bwrap.dom.appendChild(this.footer.dom);
31835 this.bg = this.el.createChild({
31836 tag: "div", cls:"x-dlg-bg",
31837 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31839 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31842 if(this.autoScroll !== false && !this.autoTabs){
31843 this.body.setStyle("overflow", "auto");
31846 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31848 if(this.closable !== false){
31849 this.el.addClass("x-dlg-closable");
31850 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31851 this.close.on("click", this.closeClick, this);
31852 this.close.addClassOnOver("x-dlg-close-over");
31854 if(this.collapsible !== false){
31855 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31856 this.collapseBtn.on("click", this.collapseClick, this);
31857 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31858 this.header.on("dblclick", this.collapseClick, this);
31860 if(this.resizable !== false){
31861 this.el.addClass("x-dlg-resizable");
31862 this.resizer = new Roo.Resizable(el, {
31863 minWidth: this.minWidth || 80,
31864 minHeight:this.minHeight || 80,
31865 handles: this.resizeHandles || "all",
31868 this.resizer.on("beforeresize", this.beforeResize, this);
31869 this.resizer.on("resize", this.onResize, this);
31871 if(this.draggable !== false){
31872 el.addClass("x-dlg-draggable");
31873 if (!this.proxyDrag) {
31874 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31877 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31879 dd.setHandleElId(this.header.id);
31880 dd.endDrag = this.endMove.createDelegate(this);
31881 dd.startDrag = this.startMove.createDelegate(this);
31882 dd.onDrag = this.onDrag.createDelegate(this);
31887 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31888 this.mask.enableDisplayMode("block");
31890 this.el.addClass("x-dlg-modal");
31893 this.shadow = new Roo.Shadow({
31894 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31895 offset : this.shadowOffset
31898 this.shadowOffset = 0;
31900 if(Roo.useShims && this.shim !== false){
31901 this.shim = this.el.createShim();
31902 this.shim.hide = this.hideAction;
31910 if (this.buttons) {
31911 var bts= this.buttons;
31913 Roo.each(bts, function(b) {
31922 * Fires when a key is pressed
31923 * @param {Roo.BasicDialog} this
31924 * @param {Roo.EventObject} e
31929 * Fires when this dialog is moved by the user.
31930 * @param {Roo.BasicDialog} this
31931 * @param {Number} x The new page X
31932 * @param {Number} y The new page Y
31937 * Fires when this dialog is resized by the user.
31938 * @param {Roo.BasicDialog} this
31939 * @param {Number} width The new width
31940 * @param {Number} height The new height
31944 * @event beforehide
31945 * Fires before this dialog is hidden.
31946 * @param {Roo.BasicDialog} this
31948 "beforehide" : true,
31951 * Fires when this dialog is hidden.
31952 * @param {Roo.BasicDialog} this
31956 * @event beforeshow
31957 * Fires before this dialog is shown.
31958 * @param {Roo.BasicDialog} this
31960 "beforeshow" : true,
31963 * Fires when this dialog is shown.
31964 * @param {Roo.BasicDialog} this
31968 el.on("keydown", this.onKeyDown, this);
31969 el.on("mousedown", this.toFront, this);
31970 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31972 Roo.DialogManager.register(this);
31973 Roo.BasicDialog.superclass.constructor.call(this);
31976 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31977 shadowOffset: Roo.isIE ? 6 : 5,
31980 minButtonWidth: 75,
31981 defaultButton: null,
31982 buttonAlign: "right",
31987 * Sets the dialog title text
31988 * @param {String} text The title text to display
31989 * @return {Roo.BasicDialog} this
31991 setTitle : function(text){
31992 this.header.update(text);
31997 closeClick : function(){
32002 collapseClick : function(){
32003 this[this.collapsed ? "expand" : "collapse"]();
32007 * Collapses the dialog to its minimized state (only the title bar is visible).
32008 * Equivalent to the user clicking the collapse dialog button.
32010 collapse : function(){
32011 if(!this.collapsed){
32012 this.collapsed = true;
32013 this.el.addClass("x-dlg-collapsed");
32014 this.restoreHeight = this.el.getHeight();
32015 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32020 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32021 * clicking the expand dialog button.
32023 expand : function(){
32024 if(this.collapsed){
32025 this.collapsed = false;
32026 this.el.removeClass("x-dlg-collapsed");
32027 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32032 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32033 * @return {Roo.TabPanel} The tabs component
32035 initTabs : function(){
32036 var tabs = this.getTabs();
32037 while(tabs.getTab(0)){
32040 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32042 tabs.addTab(Roo.id(dom), dom.title);
32050 beforeResize : function(){
32051 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32055 onResize : function(){
32056 this.refreshSize();
32057 this.syncBodyHeight();
32058 this.adjustAssets();
32060 this.fireEvent("resize", this, this.size.width, this.size.height);
32064 onKeyDown : function(e){
32065 if(this.isVisible()){
32066 this.fireEvent("keydown", this, e);
32071 * Resizes the dialog.
32072 * @param {Number} width
32073 * @param {Number} height
32074 * @return {Roo.BasicDialog} this
32076 resizeTo : function(width, height){
32077 this.el.setSize(width, height);
32078 this.size = {width: width, height: height};
32079 this.syncBodyHeight();
32080 if(this.fixedcenter){
32083 if(this.isVisible()){
32084 this.constrainXY();
32085 this.adjustAssets();
32087 this.fireEvent("resize", this, width, height);
32093 * Resizes the dialog to fit the specified content size.
32094 * @param {Number} width
32095 * @param {Number} height
32096 * @return {Roo.BasicDialog} this
32098 setContentSize : function(w, h){
32099 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32100 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32101 //if(!this.el.isBorderBox()){
32102 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32103 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32106 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32107 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32109 this.resizeTo(w, h);
32114 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32115 * executed in response to a particular key being pressed while the dialog is active.
32116 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32117 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32118 * @param {Function} fn The function to call
32119 * @param {Object} scope (optional) The scope of the function
32120 * @return {Roo.BasicDialog} this
32122 addKeyListener : function(key, fn, scope){
32123 var keyCode, shift, ctrl, alt;
32124 if(typeof key == "object" && !(key instanceof Array)){
32125 keyCode = key["key"];
32126 shift = key["shift"];
32127 ctrl = key["ctrl"];
32132 var handler = function(dlg, e){
32133 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32134 var k = e.getKey();
32135 if(keyCode instanceof Array){
32136 for(var i = 0, len = keyCode.length; i < len; i++){
32137 if(keyCode[i] == k){
32138 fn.call(scope || window, dlg, k, e);
32144 fn.call(scope || window, dlg, k, e);
32149 this.on("keydown", handler);
32154 * Returns the TabPanel component (creates it if it doesn't exist).
32155 * Note: If you wish to simply check for the existence of tabs without creating them,
32156 * check for a null 'tabs' property.
32157 * @return {Roo.TabPanel} The tabs component
32159 getTabs : function(){
32161 this.el.addClass("x-dlg-auto-tabs");
32162 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32163 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32169 * Adds a button to the footer section of the dialog.
32170 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32171 * object or a valid Roo.DomHelper element config
32172 * @param {Function} handler The function called when the button is clicked
32173 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32174 * @return {Roo.Button} The new button
32176 addButton : function(config, handler, scope){
32177 var dh = Roo.DomHelper;
32179 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32181 if(!this.btnContainer){
32182 var tb = this.footer.createChild({
32184 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32185 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32187 this.btnContainer = tb.firstChild.firstChild.firstChild;
32192 minWidth: this.minButtonWidth,
32195 if(typeof config == "string"){
32196 bconfig.text = config;
32199 bconfig.dhconfig = config;
32201 Roo.apply(bconfig, config);
32205 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32206 bconfig.position = Math.max(0, bconfig.position);
32207 fc = this.btnContainer.childNodes[bconfig.position];
32210 var btn = new Roo.Button(
32212 this.btnContainer.insertBefore(document.createElement("td"),fc)
32213 : this.btnContainer.appendChild(document.createElement("td")),
32214 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32217 this.syncBodyHeight();
32220 * Array of all the buttons that have been added to this dialog via addButton
32225 this.buttons.push(btn);
32230 * Sets the default button to be focused when the dialog is displayed.
32231 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32232 * @return {Roo.BasicDialog} this
32234 setDefaultButton : function(btn){
32235 this.defaultButton = btn;
32240 getHeaderFooterHeight : function(safe){
32243 height += this.header.getHeight();
32246 var fm = this.footer.getMargins();
32247 height += (this.footer.getHeight()+fm.top+fm.bottom);
32249 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32250 height += this.centerBg.getPadding("tb");
32255 syncBodyHeight : function()
32257 var bd = this.body, // the text
32258 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32260 var height = this.size.height - this.getHeaderFooterHeight(false);
32261 bd.setHeight(height-bd.getMargins("tb"));
32262 var hh = this.header.getHeight();
32263 var h = this.size.height-hh;
32266 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32267 bw.setHeight(h-cb.getPadding("tb"));
32269 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32270 bd.setWidth(bw.getWidth(true));
32272 this.tabs.syncHeight();
32274 this.tabs.el.repaint();
32280 * Restores the previous state of the dialog if Roo.state is configured.
32281 * @return {Roo.BasicDialog} this
32283 restoreState : function(){
32284 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32285 if(box && box.width){
32286 this.xy = [box.x, box.y];
32287 this.resizeTo(box.width, box.height);
32293 beforeShow : function(){
32295 if(this.fixedcenter){
32296 this.xy = this.el.getCenterXY(true);
32299 Roo.get(document.body).addClass("x-body-masked");
32300 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32303 this.constrainXY();
32307 animShow : function(){
32308 var b = Roo.get(this.animateTarget).getBox();
32309 this.proxy.setSize(b.width, b.height);
32310 this.proxy.setLocation(b.x, b.y);
32312 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32313 true, .35, this.showEl.createDelegate(this));
32317 * Shows the dialog.
32318 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32319 * @return {Roo.BasicDialog} this
32321 show : function(animateTarget){
32322 if (this.fireEvent("beforeshow", this) === false){
32325 if(this.syncHeightBeforeShow){
32326 this.syncBodyHeight();
32327 }else if(this.firstShow){
32328 this.firstShow = false;
32329 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32331 this.animateTarget = animateTarget || this.animateTarget;
32332 if(!this.el.isVisible()){
32334 if(this.animateTarget && Roo.get(this.animateTarget)){
32344 showEl : function(){
32346 this.el.setXY(this.xy);
32348 this.adjustAssets(true);
32351 // IE peekaboo bug - fix found by Dave Fenwick
32355 this.fireEvent("show", this);
32359 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32360 * dialog itself will receive focus.
32362 focus : function(){
32363 if(this.defaultButton){
32364 this.defaultButton.focus();
32366 this.focusEl.focus();
32371 constrainXY : function(){
32372 if(this.constraintoviewport !== false){
32373 if(!this.viewSize){
32374 if(this.container){
32375 var s = this.container.getSize();
32376 this.viewSize = [s.width, s.height];
32378 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32381 var s = Roo.get(this.container||document).getScroll();
32383 var x = this.xy[0], y = this.xy[1];
32384 var w = this.size.width, h = this.size.height;
32385 var vw = this.viewSize[0], vh = this.viewSize[1];
32386 // only move it if it needs it
32388 // first validate right/bottom
32389 if(x + w > vw+s.left){
32393 if(y + h > vh+s.top){
32397 // then make sure top/left isn't negative
32409 if(this.isVisible()){
32410 this.el.setLocation(x, y);
32411 this.adjustAssets();
32418 onDrag : function(){
32419 if(!this.proxyDrag){
32420 this.xy = this.el.getXY();
32421 this.adjustAssets();
32426 adjustAssets : function(doShow){
32427 var x = this.xy[0], y = this.xy[1];
32428 var w = this.size.width, h = this.size.height;
32429 if(doShow === true){
32431 this.shadow.show(this.el);
32437 if(this.shadow && this.shadow.isVisible()){
32438 this.shadow.show(this.el);
32440 if(this.shim && this.shim.isVisible()){
32441 this.shim.setBounds(x, y, w, h);
32446 adjustViewport : function(w, h){
32448 w = Roo.lib.Dom.getViewWidth();
32449 h = Roo.lib.Dom.getViewHeight();
32452 this.viewSize = [w, h];
32453 if(this.modal && this.mask.isVisible()){
32454 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32455 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32457 if(this.isVisible()){
32458 this.constrainXY();
32463 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32464 * shadow, proxy, mask, etc.) Also removes all event listeners.
32465 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32467 destroy : function(removeEl){
32468 if(this.isVisible()){
32469 this.animateTarget = null;
32472 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32474 this.tabs.destroy(removeEl);
32487 for(var i = 0, len = this.buttons.length; i < len; i++){
32488 this.buttons[i].destroy();
32491 this.el.removeAllListeners();
32492 if(removeEl === true){
32493 this.el.update("");
32496 Roo.DialogManager.unregister(this);
32500 startMove : function(){
32501 if(this.proxyDrag){
32504 if(this.constraintoviewport !== false){
32505 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32510 endMove : function(){
32511 if(!this.proxyDrag){
32512 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32514 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32517 this.refreshSize();
32518 this.adjustAssets();
32520 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32524 * Brings this dialog to the front of any other visible dialogs
32525 * @return {Roo.BasicDialog} this
32527 toFront : function(){
32528 Roo.DialogManager.bringToFront(this);
32533 * Sends this dialog to the back (under) of any other visible dialogs
32534 * @return {Roo.BasicDialog} this
32536 toBack : function(){
32537 Roo.DialogManager.sendToBack(this);
32542 * Centers this dialog in the viewport
32543 * @return {Roo.BasicDialog} this
32545 center : function(){
32546 var xy = this.el.getCenterXY(true);
32547 this.moveTo(xy[0], xy[1]);
32552 * Moves the dialog's top-left corner to the specified point
32553 * @param {Number} x
32554 * @param {Number} y
32555 * @return {Roo.BasicDialog} this
32557 moveTo : function(x, y){
32559 if(this.isVisible()){
32560 this.el.setXY(this.xy);
32561 this.adjustAssets();
32567 * Aligns the dialog to the specified element
32568 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32569 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32570 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32571 * @return {Roo.BasicDialog} this
32573 alignTo : function(element, position, offsets){
32574 this.xy = this.el.getAlignToXY(element, position, offsets);
32575 if(this.isVisible()){
32576 this.el.setXY(this.xy);
32577 this.adjustAssets();
32583 * Anchors an element to another element and realigns it when the window is resized.
32584 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32585 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32586 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32587 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32588 * is a number, it is used as the buffer delay (defaults to 50ms).
32589 * @return {Roo.BasicDialog} this
32591 anchorTo : function(el, alignment, offsets, monitorScroll){
32592 var action = function(){
32593 this.alignTo(el, alignment, offsets);
32595 Roo.EventManager.onWindowResize(action, this);
32596 var tm = typeof monitorScroll;
32597 if(tm != 'undefined'){
32598 Roo.EventManager.on(window, 'scroll', action, this,
32599 {buffer: tm == 'number' ? monitorScroll : 50});
32606 * Returns true if the dialog is visible
32607 * @return {Boolean}
32609 isVisible : function(){
32610 return this.el.isVisible();
32614 animHide : function(callback){
32615 var b = Roo.get(this.animateTarget).getBox();
32617 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32619 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32620 this.hideEl.createDelegate(this, [callback]));
32624 * Hides the dialog.
32625 * @param {Function} callback (optional) Function to call when the dialog is hidden
32626 * @return {Roo.BasicDialog} this
32628 hide : function(callback){
32629 if (this.fireEvent("beforehide", this) === false){
32633 this.shadow.hide();
32638 // sometimes animateTarget seems to get set.. causing problems...
32639 // this just double checks..
32640 if(this.animateTarget && Roo.get(this.animateTarget)) {
32641 this.animHide(callback);
32644 this.hideEl(callback);
32650 hideEl : function(callback){
32654 Roo.get(document.body).removeClass("x-body-masked");
32656 this.fireEvent("hide", this);
32657 if(typeof callback == "function"){
32663 hideAction : function(){
32664 this.setLeft("-10000px");
32665 this.setTop("-10000px");
32666 this.setStyle("visibility", "hidden");
32670 refreshSize : function(){
32671 this.size = this.el.getSize();
32672 this.xy = this.el.getXY();
32673 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32677 // z-index is managed by the DialogManager and may be overwritten at any time
32678 setZIndex : function(index){
32680 this.mask.setStyle("z-index", index);
32683 this.shim.setStyle("z-index", ++index);
32686 this.shadow.setZIndex(++index);
32688 this.el.setStyle("z-index", ++index);
32690 this.proxy.setStyle("z-index", ++index);
32693 this.resizer.proxy.setStyle("z-index", ++index);
32696 this.lastZIndex = index;
32700 * Returns the element for this dialog
32701 * @return {Roo.Element} The underlying dialog Element
32703 getEl : function(){
32709 * @class Roo.DialogManager
32710 * Provides global access to BasicDialogs that have been created and
32711 * support for z-indexing (layering) multiple open dialogs.
32713 Roo.DialogManager = function(){
32715 var accessList = [];
32719 var sortDialogs = function(d1, d2){
32720 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32724 var orderDialogs = function(){
32725 accessList.sort(sortDialogs);
32726 var seed = Roo.DialogManager.zseed;
32727 for(var i = 0, len = accessList.length; i < len; i++){
32728 var dlg = accessList[i];
32730 dlg.setZIndex(seed + (i*10));
32737 * The starting z-index for BasicDialogs (defaults to 9000)
32738 * @type Number The z-index value
32743 register : function(dlg){
32744 list[dlg.id] = dlg;
32745 accessList.push(dlg);
32749 unregister : function(dlg){
32750 delete list[dlg.id];
32753 if(!accessList.indexOf){
32754 for( i = 0, len = accessList.length; i < len; i++){
32755 if(accessList[i] == dlg){
32756 accessList.splice(i, 1);
32761 i = accessList.indexOf(dlg);
32763 accessList.splice(i, 1);
32769 * Gets a registered dialog by id
32770 * @param {String/Object} id The id of the dialog or a dialog
32771 * @return {Roo.BasicDialog} this
32773 get : function(id){
32774 return typeof id == "object" ? id : list[id];
32778 * Brings the specified dialog to the front
32779 * @param {String/Object} dlg The id of the dialog or a dialog
32780 * @return {Roo.BasicDialog} this
32782 bringToFront : function(dlg){
32783 dlg = this.get(dlg);
32786 dlg._lastAccess = new Date().getTime();
32793 * Sends the specified dialog to the back
32794 * @param {String/Object} dlg The id of the dialog or a dialog
32795 * @return {Roo.BasicDialog} this
32797 sendToBack : function(dlg){
32798 dlg = this.get(dlg);
32799 dlg._lastAccess = -(new Date().getTime());
32805 * Hides all dialogs
32807 hideAll : function(){
32808 for(var id in list){
32809 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32818 * @class Roo.LayoutDialog
32819 * @extends Roo.BasicDialog
32820 * Dialog which provides adjustments for working with a layout in a Dialog.
32821 * Add your necessary layout config options to the dialog's config.<br>
32822 * Example usage (including a nested layout):
32825 dialog = new Roo.LayoutDialog("download-dlg", {
32834 // layout config merges with the dialog config
32836 tabPosition: "top",
32837 alwaysShowTabs: true
32840 dialog.addKeyListener(27, dialog.hide, dialog);
32841 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32842 dialog.addButton("Build It!", this.getDownload, this);
32844 // we can even add nested layouts
32845 var innerLayout = new Roo.BorderLayout("dl-inner", {
32855 innerLayout.beginUpdate();
32856 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32857 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32858 innerLayout.endUpdate(true);
32860 var layout = dialog.getLayout();
32861 layout.beginUpdate();
32862 layout.add("center", new Roo.ContentPanel("standard-panel",
32863 {title: "Download the Source", fitToFrame:true}));
32864 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32865 {title: "Build your own roo.js"}));
32866 layout.getRegion("center").showPanel(sp);
32867 layout.endUpdate();
32871 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32872 * @param {Object} config configuration options
32874 Roo.LayoutDialog = function(el, cfg){
32877 if (typeof(cfg) == 'undefined') {
32878 config = Roo.apply({}, el);
32879 // not sure why we use documentElement here.. - it should always be body.
32880 // IE7 borks horribly if we use documentElement.
32881 // webkit also does not like documentElement - it creates a body element...
32882 el = Roo.get( document.body || document.documentElement ).createChild();
32883 //config.autoCreate = true;
32887 config.autoTabs = false;
32888 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32889 this.body.setStyle({overflow:"hidden", position:"relative"});
32890 this.layout = new Roo.BorderLayout(this.body.dom, config);
32891 this.layout.monitorWindowResize = false;
32892 this.el.addClass("x-dlg-auto-layout");
32893 // fix case when center region overwrites center function
32894 this.center = Roo.BasicDialog.prototype.center;
32895 this.on("show", this.layout.layout, this.layout, true);
32896 if (config.items) {
32897 var xitems = config.items;
32898 delete config.items;
32899 Roo.each(xitems, this.addxtype, this);
32904 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32906 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32909 endUpdate : function(){
32910 this.layout.endUpdate();
32914 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32917 beginUpdate : function(){
32918 this.layout.beginUpdate();
32922 * Get the BorderLayout for this dialog
32923 * @return {Roo.BorderLayout}
32925 getLayout : function(){
32926 return this.layout;
32929 showEl : function(){
32930 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32932 this.layout.layout();
32937 // Use the syncHeightBeforeShow config option to control this automatically
32938 syncBodyHeight : function(){
32939 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32940 if(this.layout){this.layout.layout();}
32944 * Add an xtype element (actually adds to the layout.)
32945 * @return {Object} xdata xtype object data.
32948 addxtype : function(c) {
32949 return this.layout.addxtype(c);
32953 * Ext JS Library 1.1.1
32954 * Copyright(c) 2006-2007, Ext JS, LLC.
32956 * Originally Released Under LGPL - original licence link has changed is not relivant.
32959 * <script type="text/javascript">
32963 * @class Roo.MessageBox
32964 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32968 Roo.Msg.alert('Status', 'Changes saved successfully.');
32970 // Prompt for user data:
32971 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32973 // process text value...
32977 // Show a dialog using config options:
32979 title:'Save Changes?',
32980 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32981 buttons: Roo.Msg.YESNOCANCEL,
32988 Roo.MessageBox = function(){
32989 var dlg, opt, mask, waitTimer;
32990 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32991 var buttons, activeTextEl, bwidth;
32994 var handleButton = function(button){
32996 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33000 var handleHide = function(){
33001 if(opt && opt.cls){
33002 dlg.el.removeClass(opt.cls);
33005 Roo.TaskMgr.stop(waitTimer);
33011 var updateButtons = function(b){
33014 buttons["ok"].hide();
33015 buttons["cancel"].hide();
33016 buttons["yes"].hide();
33017 buttons["no"].hide();
33018 dlg.footer.dom.style.display = 'none';
33021 dlg.footer.dom.style.display = '';
33022 for(var k in buttons){
33023 if(typeof buttons[k] != "function"){
33026 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33027 width += buttons[k].el.getWidth()+15;
33037 var handleEsc = function(d, k, e){
33038 if(opt && opt.closable !== false){
33048 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33049 * @return {Roo.BasicDialog} The BasicDialog element
33051 getDialog : function(){
33053 dlg = new Roo.BasicDialog("x-msg-box", {
33058 constraintoviewport:false,
33060 collapsible : false,
33063 width:400, height:100,
33064 buttonAlign:"center",
33065 closeClick : function(){
33066 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33067 handleButton("no");
33069 handleButton("cancel");
33073 dlg.on("hide", handleHide);
33075 dlg.addKeyListener(27, handleEsc);
33077 var bt = this.buttonText;
33078 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33079 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33080 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33081 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33082 bodyEl = dlg.body.createChild({
33084 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>'
33086 msgEl = bodyEl.dom.firstChild;
33087 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33088 textboxEl.enableDisplayMode();
33089 textboxEl.addKeyListener([10,13], function(){
33090 if(dlg.isVisible() && opt && opt.buttons){
33091 if(opt.buttons.ok){
33092 handleButton("ok");
33093 }else if(opt.buttons.yes){
33094 handleButton("yes");
33098 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33099 textareaEl.enableDisplayMode();
33100 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33101 progressEl.enableDisplayMode();
33102 var pf = progressEl.dom.firstChild;
33104 pp = Roo.get(pf.firstChild);
33105 pp.setHeight(pf.offsetHeight);
33113 * Updates the message box body text
33114 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33115 * the XHTML-compliant non-breaking space character '&#160;')
33116 * @return {Roo.MessageBox} This message box
33118 updateText : function(text){
33119 if(!dlg.isVisible() && !opt.width){
33120 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33122 msgEl.innerHTML = text || ' ';
33124 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33125 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33127 Math.min(opt.width || cw , this.maxWidth),
33128 Math.max(opt.minWidth || this.minWidth, bwidth)
33131 activeTextEl.setWidth(w);
33133 if(dlg.isVisible()){
33134 dlg.fixedcenter = false;
33136 // to big, make it scroll. = But as usual stupid IE does not support
33139 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33140 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33141 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33143 bodyEl.dom.style.height = '';
33144 bodyEl.dom.style.overflowY = '';
33147 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33149 bodyEl.dom.style.overflowX = '';
33152 dlg.setContentSize(w, bodyEl.getHeight());
33153 if(dlg.isVisible()){
33154 dlg.fixedcenter = true;
33160 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33161 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33162 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33163 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33164 * @return {Roo.MessageBox} This message box
33166 updateProgress : function(value, text){
33168 this.updateText(text);
33170 if (pp) { // weird bug on my firefox - for some reason this is not defined
33171 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33177 * Returns true if the message box is currently displayed
33178 * @return {Boolean} True if the message box is visible, else false
33180 isVisible : function(){
33181 return dlg && dlg.isVisible();
33185 * Hides the message box if it is displayed
33188 if(this.isVisible()){
33194 * Displays a new message box, or reinitializes an existing message box, based on the config options
33195 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33196 * The following config object properties are supported:
33198 Property Type Description
33199 ---------- --------------- ------------------------------------------------------------------------------------
33200 animEl String/Element An id or Element from which the message box should animate as it opens and
33201 closes (defaults to undefined)
33202 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33203 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33204 closable Boolean False to hide the top-right close button (defaults to true). Note that
33205 progress and wait dialogs will ignore this property and always hide the
33206 close button as they can only be closed programmatically.
33207 cls String A custom CSS class to apply to the message box element
33208 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33209 displayed (defaults to 75)
33210 fn Function A callback function to execute after closing the dialog. The arguments to the
33211 function will be btn (the name of the button that was clicked, if applicable,
33212 e.g. "ok"), and text (the value of the active text field, if applicable).
33213 Progress and wait dialogs will ignore this option since they do not respond to
33214 user actions and can only be closed programmatically, so any required function
33215 should be called by the same code after it closes the dialog.
33216 icon String A CSS class that provides a background image to be used as an icon for
33217 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33218 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33219 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33220 modal Boolean False to allow user interaction with the page while the message box is
33221 displayed (defaults to true)
33222 msg String A string that will replace the existing message box body text (defaults
33223 to the XHTML-compliant non-breaking space character ' ')
33224 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33225 progress Boolean True to display a progress bar (defaults to false)
33226 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33227 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33228 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33229 title String The title text
33230 value String The string value to set into the active textbox element if displayed
33231 wait Boolean True to display a progress bar (defaults to false)
33232 width Number The width of the dialog in pixels
33239 msg: 'Please enter your address:',
33241 buttons: Roo.MessageBox.OKCANCEL,
33244 animEl: 'addAddressBtn'
33247 * @param {Object} config Configuration options
33248 * @return {Roo.MessageBox} This message box
33250 show : function(options)
33253 // this causes nightmares if you show one dialog after another
33254 // especially on callbacks..
33256 if(this.isVisible()){
33259 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33260 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33261 Roo.log("New Dialog Message:" + options.msg )
33262 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33263 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33266 var d = this.getDialog();
33268 d.setTitle(opt.title || " ");
33269 d.close.setDisplayed(opt.closable !== false);
33270 activeTextEl = textboxEl;
33271 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33276 textareaEl.setHeight(typeof opt.multiline == "number" ?
33277 opt.multiline : this.defaultTextHeight);
33278 activeTextEl = textareaEl;
33287 progressEl.setDisplayed(opt.progress === true);
33288 this.updateProgress(0);
33289 activeTextEl.dom.value = opt.value || "";
33291 dlg.setDefaultButton(activeTextEl);
33293 var bs = opt.buttons;
33296 db = buttons["ok"];
33297 }else if(bs && bs.yes){
33298 db = buttons["yes"];
33300 dlg.setDefaultButton(db);
33302 bwidth = updateButtons(opt.buttons);
33303 this.updateText(opt.msg);
33305 d.el.addClass(opt.cls);
33307 d.proxyDrag = opt.proxyDrag === true;
33308 d.modal = opt.modal !== false;
33309 d.mask = opt.modal !== false ? mask : false;
33310 if(!d.isVisible()){
33311 // force it to the end of the z-index stack so it gets a cursor in FF
33312 document.body.appendChild(dlg.el.dom);
33313 d.animateTarget = null;
33314 d.show(options.animEl);
33320 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33321 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33322 * and closing the message box when the process is complete.
33323 * @param {String} title The title bar text
33324 * @param {String} msg The message box body text
33325 * @return {Roo.MessageBox} This message box
33327 progress : function(title, msg){
33334 minWidth: this.minProgressWidth,
33341 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33342 * If a callback function is passed it will be called after the user clicks the button, and the
33343 * id of the button that was clicked will be passed as the only parameter to the callback
33344 * (could also be the top-right close button).
33345 * @param {String} title The title bar text
33346 * @param {String} msg The message box body text
33347 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33348 * @param {Object} scope (optional) The scope of the callback function
33349 * @return {Roo.MessageBox} This message box
33351 alert : function(title, msg, fn, scope){
33364 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33365 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33366 * You are responsible for closing the message box when the process is complete.
33367 * @param {String} msg The message box body text
33368 * @param {String} title (optional) The title bar text
33369 * @return {Roo.MessageBox} This message box
33371 wait : function(msg, title){
33382 waitTimer = Roo.TaskMgr.start({
33384 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33392 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33393 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33394 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33395 * @param {String} title The title bar text
33396 * @param {String} msg The message box body text
33397 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33398 * @param {Object} scope (optional) The scope of the callback function
33399 * @return {Roo.MessageBox} This message box
33401 confirm : function(title, msg, fn, scope){
33405 buttons: this.YESNO,
33414 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33415 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33416 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33417 * (could also be the top-right close button) and the text that was entered will be passed as the two
33418 * parameters to the callback.
33419 * @param {String} title The title bar text
33420 * @param {String} msg The message box body text
33421 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33422 * @param {Object} scope (optional) The scope of the callback function
33423 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33424 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33425 * @return {Roo.MessageBox} This message box
33427 prompt : function(title, msg, fn, scope, multiline){
33431 buttons: this.OKCANCEL,
33436 multiline: multiline,
33443 * Button config that displays a single OK button
33448 * Button config that displays Yes and No buttons
33451 YESNO : {yes:true, no:true},
33453 * Button config that displays OK and Cancel buttons
33456 OKCANCEL : {ok:true, cancel:true},
33458 * Button config that displays Yes, No and Cancel buttons
33461 YESNOCANCEL : {yes:true, no:true, cancel:true},
33464 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33467 defaultTextHeight : 75,
33469 * The maximum width in pixels of the message box (defaults to 600)
33474 * The minimum width in pixels of the message box (defaults to 100)
33479 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33480 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33483 minProgressWidth : 250,
33485 * An object containing the default button text strings that can be overriden for localized language support.
33486 * Supported properties are: ok, cancel, yes and no.
33487 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33500 * Shorthand for {@link Roo.MessageBox}
33502 Roo.Msg = Roo.MessageBox;/*
33504 * Ext JS Library 1.1.1
33505 * Copyright(c) 2006-2007, Ext JS, LLC.
33507 * Originally Released Under LGPL - original licence link has changed is not relivant.
33510 * <script type="text/javascript">
33513 * @class Roo.QuickTips
33514 * Provides attractive and customizable tooltips for any element.
33517 Roo.QuickTips = function(){
33518 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33519 var ce, bd, xy, dd;
33520 var visible = false, disabled = true, inited = false;
33521 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33523 var onOver = function(e){
33527 var t = e.getTarget();
33528 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33531 if(ce && t == ce.el){
33532 clearTimeout(hideProc);
33535 if(t && tagEls[t.id]){
33536 tagEls[t.id].el = t;
33537 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33540 var ttp, et = Roo.fly(t);
33541 var ns = cfg.namespace;
33542 if(tm.interceptTitles && t.title){
33545 t.removeAttribute("title");
33546 e.preventDefault();
33548 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33551 showProc = show.defer(tm.showDelay, tm, [{
33554 width: et.getAttributeNS(ns, cfg.width),
33555 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33556 title: et.getAttributeNS(ns, cfg.title),
33557 cls: et.getAttributeNS(ns, cfg.cls)
33562 var onOut = function(e){
33563 clearTimeout(showProc);
33564 var t = e.getTarget();
33565 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33566 hideProc = setTimeout(hide, tm.hideDelay);
33570 var onMove = function(e){
33576 if(tm.trackMouse && ce){
33581 var onDown = function(e){
33582 clearTimeout(showProc);
33583 clearTimeout(hideProc);
33585 if(tm.hideOnClick){
33588 tm.enable.defer(100, tm);
33593 var getPad = function(){
33594 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33597 var show = function(o){
33601 clearTimeout(dismissProc);
33603 if(removeCls){ // in case manually hidden
33604 el.removeClass(removeCls);
33608 el.addClass(ce.cls);
33609 removeCls = ce.cls;
33612 tipTitle.update(ce.title);
33615 tipTitle.update('');
33618 el.dom.style.width = tm.maxWidth+'px';
33619 //tipBody.dom.style.width = '';
33620 tipBodyText.update(o.text);
33621 var p = getPad(), w = ce.width;
33623 var td = tipBodyText.dom;
33624 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33625 if(aw > tm.maxWidth){
33627 }else if(aw < tm.minWidth){
33633 //tipBody.setWidth(w);
33634 el.setWidth(parseInt(w, 10) + p);
33635 if(ce.autoHide === false){
33636 close.setDisplayed(true);
33641 close.setDisplayed(false);
33647 el.avoidY = xy[1]-18;
33652 el.setStyle("visibility", "visible");
33653 el.fadeIn({callback: afterShow});
33659 var afterShow = function(){
33663 if(tm.autoDismiss && ce.autoHide !== false){
33664 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33669 var hide = function(noanim){
33670 clearTimeout(dismissProc);
33671 clearTimeout(hideProc);
33673 if(el.isVisible()){
33675 if(noanim !== true && tm.animate){
33676 el.fadeOut({callback: afterHide});
33683 var afterHide = function(){
33686 el.removeClass(removeCls);
33693 * @cfg {Number} minWidth
33694 * The minimum width of the quick tip (defaults to 40)
33698 * @cfg {Number} maxWidth
33699 * The maximum width of the quick tip (defaults to 300)
33703 * @cfg {Boolean} interceptTitles
33704 * True to automatically use the element's DOM title value if available (defaults to false)
33706 interceptTitles : false,
33708 * @cfg {Boolean} trackMouse
33709 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33711 trackMouse : false,
33713 * @cfg {Boolean} hideOnClick
33714 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33716 hideOnClick : true,
33718 * @cfg {Number} showDelay
33719 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33723 * @cfg {Number} hideDelay
33724 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33728 * @cfg {Boolean} autoHide
33729 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33730 * Used in conjunction with hideDelay.
33735 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33736 * (defaults to true). Used in conjunction with autoDismissDelay.
33738 autoDismiss : true,
33741 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33743 autoDismissDelay : 5000,
33745 * @cfg {Boolean} animate
33746 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33751 * @cfg {String} title
33752 * Title text to display (defaults to ''). This can be any valid HTML markup.
33756 * @cfg {String} text
33757 * Body text to display (defaults to ''). This can be any valid HTML markup.
33761 * @cfg {String} cls
33762 * A CSS class to apply to the base quick tip element (defaults to '').
33766 * @cfg {Number} width
33767 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33768 * minWidth or maxWidth.
33773 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33774 * or display QuickTips in a page.
33777 tm = Roo.QuickTips;
33778 cfg = tm.tagConfig;
33780 if(!Roo.isReady){ // allow calling of init() before onReady
33781 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33784 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33785 el.fxDefaults = {stopFx: true};
33786 // maximum custom styling
33787 //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>');
33788 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>');
33789 tipTitle = el.child('h3');
33790 tipTitle.enableDisplayMode("block");
33791 tipBody = el.child('div.x-tip-bd');
33792 tipBodyText = el.child('div.x-tip-bd-inner');
33793 //bdLeft = el.child('div.x-tip-bd-left');
33794 //bdRight = el.child('div.x-tip-bd-right');
33795 close = el.child('div.x-tip-close');
33796 close.enableDisplayMode("block");
33797 close.on("click", hide);
33798 var d = Roo.get(document);
33799 d.on("mousedown", onDown);
33800 d.on("mouseover", onOver);
33801 d.on("mouseout", onOut);
33802 d.on("mousemove", onMove);
33803 esc = d.addKeyListener(27, hide);
33806 dd = el.initDD("default", null, {
33807 onDrag : function(){
33811 dd.setHandleElId(tipTitle.id);
33820 * Configures a new quick tip instance and assigns it to a target element. The following config options
33823 Property Type Description
33824 ---------- --------------------- ------------------------------------------------------------------------
33825 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33827 * @param {Object} config The config object
33829 register : function(config){
33830 var cs = config instanceof Array ? config : arguments;
33831 for(var i = 0, len = cs.length; i < len; i++) {
33833 var target = c.target;
33835 if(target instanceof Array){
33836 for(var j = 0, jlen = target.length; j < jlen; j++){
33837 tagEls[target[j]] = c;
33840 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33847 * Removes this quick tip from its element and destroys it.
33848 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33850 unregister : function(el){
33851 delete tagEls[Roo.id(el)];
33855 * Enable this quick tip.
33857 enable : function(){
33858 if(inited && disabled){
33860 if(locks.length < 1){
33867 * Disable this quick tip.
33869 disable : function(){
33871 clearTimeout(showProc);
33872 clearTimeout(hideProc);
33873 clearTimeout(dismissProc);
33881 * Returns true if the quick tip is enabled, else false.
33883 isEnabled : function(){
33889 namespace : "roo", // was ext?? this may break..
33890 alt_namespace : "ext",
33891 attribute : "qtip",
33901 // backwards compat
33902 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33904 * Ext JS Library 1.1.1
33905 * Copyright(c) 2006-2007, Ext JS, LLC.
33907 * Originally Released Under LGPL - original licence link has changed is not relivant.
33910 * <script type="text/javascript">
33915 * @class Roo.tree.TreePanel
33916 * @extends Roo.data.Tree
33918 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33919 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33920 * @cfg {Boolean} enableDD true to enable drag and drop
33921 * @cfg {Boolean} enableDrag true to enable just drag
33922 * @cfg {Boolean} enableDrop true to enable just drop
33923 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33924 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33925 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33926 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33927 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33928 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33929 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33930 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33931 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33932 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33933 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33934 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33935 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33936 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33937 * @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>
33938 * @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>
33941 * @param {String/HTMLElement/Element} el The container element
33942 * @param {Object} config
33944 Roo.tree.TreePanel = function(el, config){
33946 var loader = false;
33948 root = config.root;
33949 delete config.root;
33951 if (config.loader) {
33952 loader = config.loader;
33953 delete config.loader;
33956 Roo.apply(this, config);
33957 Roo.tree.TreePanel.superclass.constructor.call(this);
33958 this.el = Roo.get(el);
33959 this.el.addClass('x-tree');
33960 //console.log(root);
33962 this.setRootNode( Roo.factory(root, Roo.tree));
33965 this.loader = Roo.factory(loader, Roo.tree);
33968 * Read-only. The id of the container element becomes this TreePanel's id.
33970 this.id = this.el.id;
33973 * @event beforeload
33974 * Fires before a node is loaded, return false to cancel
33975 * @param {Node} node The node being loaded
33977 "beforeload" : true,
33980 * Fires when a node is loaded
33981 * @param {Node} node The node that was loaded
33985 * @event textchange
33986 * Fires when the text for a node is changed
33987 * @param {Node} node The node
33988 * @param {String} text The new text
33989 * @param {String} oldText The old text
33991 "textchange" : true,
33993 * @event beforeexpand
33994 * Fires before a node is expanded, return false to cancel.
33995 * @param {Node} node The node
33996 * @param {Boolean} deep
33997 * @param {Boolean} anim
33999 "beforeexpand" : true,
34001 * @event beforecollapse
34002 * Fires before a node is collapsed, return false to cancel.
34003 * @param {Node} node The node
34004 * @param {Boolean} deep
34005 * @param {Boolean} anim
34007 "beforecollapse" : true,
34010 * Fires when a node is expanded
34011 * @param {Node} node The node
34015 * @event disabledchange
34016 * Fires when the disabled status of a node changes
34017 * @param {Node} node The node
34018 * @param {Boolean} disabled
34020 "disabledchange" : true,
34023 * Fires when a node is collapsed
34024 * @param {Node} node The node
34028 * @event beforeclick
34029 * Fires before click processing on a node. Return false to cancel the default action.
34030 * @param {Node} node The node
34031 * @param {Roo.EventObject} e The event object
34033 "beforeclick":true,
34035 * @event checkchange
34036 * Fires when a node with a checkbox's checked property changes
34037 * @param {Node} this This node
34038 * @param {Boolean} checked
34040 "checkchange":true,
34043 * Fires when a node is clicked
34044 * @param {Node} node The node
34045 * @param {Roo.EventObject} e The event object
34050 * Fires when a node is double clicked
34051 * @param {Node} node The node
34052 * @param {Roo.EventObject} e The event object
34056 * @event contextmenu
34057 * Fires when a node is right clicked
34058 * @param {Node} node The node
34059 * @param {Roo.EventObject} e The event object
34061 "contextmenu":true,
34063 * @event beforechildrenrendered
34064 * Fires right before the child nodes for a node are rendered
34065 * @param {Node} node The node
34067 "beforechildrenrendered":true,
34070 * Fires when a node starts being dragged
34071 * @param {Roo.tree.TreePanel} this
34072 * @param {Roo.tree.TreeNode} node
34073 * @param {event} e The raw browser event
34075 "startdrag" : true,
34078 * Fires when a drag operation is complete
34079 * @param {Roo.tree.TreePanel} this
34080 * @param {Roo.tree.TreeNode} node
34081 * @param {event} e The raw browser event
34086 * Fires when a dragged node is dropped on a valid DD target
34087 * @param {Roo.tree.TreePanel} this
34088 * @param {Roo.tree.TreeNode} node
34089 * @param {DD} dd The dd it was dropped on
34090 * @param {event} e The raw browser event
34094 * @event beforenodedrop
34095 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34096 * passed to handlers has the following properties:<br />
34097 * <ul style="padding:5px;padding-left:16px;">
34098 * <li>tree - The TreePanel</li>
34099 * <li>target - The node being targeted for the drop</li>
34100 * <li>data - The drag data from the drag source</li>
34101 * <li>point - The point of the drop - append, above or below</li>
34102 * <li>source - The drag source</li>
34103 * <li>rawEvent - Raw mouse event</li>
34104 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34105 * to be inserted by setting them on this object.</li>
34106 * <li>cancel - Set this to true to cancel the drop.</li>
34108 * @param {Object} dropEvent
34110 "beforenodedrop" : true,
34113 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34114 * passed to handlers has the following properties:<br />
34115 * <ul style="padding:5px;padding-left:16px;">
34116 * <li>tree - The TreePanel</li>
34117 * <li>target - The node being targeted for the drop</li>
34118 * <li>data - The drag data from the drag source</li>
34119 * <li>point - The point of the drop - append, above or below</li>
34120 * <li>source - The drag source</li>
34121 * <li>rawEvent - Raw mouse event</li>
34122 * <li>dropNode - Dropped node(s).</li>
34124 * @param {Object} dropEvent
34128 * @event nodedragover
34129 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34130 * passed to handlers has the following properties:<br />
34131 * <ul style="padding:5px;padding-left:16px;">
34132 * <li>tree - The TreePanel</li>
34133 * <li>target - The node being targeted for the drop</li>
34134 * <li>data - The drag data from the drag source</li>
34135 * <li>point - The point of the drop - append, above or below</li>
34136 * <li>source - The drag source</li>
34137 * <li>rawEvent - Raw mouse event</li>
34138 * <li>dropNode - Drop node(s) provided by the source.</li>
34139 * <li>cancel - Set this to true to signal drop not allowed.</li>
34141 * @param {Object} dragOverEvent
34143 "nodedragover" : true
34146 if(this.singleExpand){
34147 this.on("beforeexpand", this.restrictExpand, this);
34150 this.editor.tree = this;
34151 this.editor = Roo.factory(this.editor, Roo.tree);
34154 if (this.selModel) {
34155 this.selModel = Roo.factory(this.selModel, Roo.tree);
34159 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34160 rootVisible : true,
34161 animate: Roo.enableFx,
34164 hlDrop : Roo.enableFx,
34168 rendererTip: false,
34170 restrictExpand : function(node){
34171 var p = node.parentNode;
34173 if(p.expandedChild && p.expandedChild.parentNode == p){
34174 p.expandedChild.collapse();
34176 p.expandedChild = node;
34180 // private override
34181 setRootNode : function(node){
34182 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34183 if(!this.rootVisible){
34184 node.ui = new Roo.tree.RootTreeNodeUI(node);
34190 * Returns the container element for this TreePanel
34192 getEl : function(){
34197 * Returns the default TreeLoader for this TreePanel
34199 getLoader : function(){
34200 return this.loader;
34206 expandAll : function(){
34207 this.root.expand(true);
34211 * Collapse all nodes
34213 collapseAll : function(){
34214 this.root.collapse(true);
34218 * Returns the selection model used by this TreePanel
34220 getSelectionModel : function(){
34221 if(!this.selModel){
34222 this.selModel = new Roo.tree.DefaultSelectionModel();
34224 return this.selModel;
34228 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34229 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34230 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34233 getChecked : function(a, startNode){
34234 startNode = startNode || this.root;
34236 var f = function(){
34237 if(this.attributes.checked){
34238 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34241 startNode.cascade(f);
34246 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34247 * @param {String} path
34248 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34249 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34250 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34252 expandPath : function(path, attr, callback){
34253 attr = attr || "id";
34254 var keys = path.split(this.pathSeparator);
34255 var curNode = this.root;
34256 if(curNode.attributes[attr] != keys[1]){ // invalid root
34258 callback(false, null);
34263 var f = function(){
34264 if(++index == keys.length){
34266 callback(true, curNode);
34270 var c = curNode.findChild(attr, keys[index]);
34273 callback(false, curNode);
34278 c.expand(false, false, f);
34280 curNode.expand(false, false, f);
34284 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34285 * @param {String} path
34286 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34287 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34288 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34290 selectPath : function(path, attr, callback){
34291 attr = attr || "id";
34292 var keys = path.split(this.pathSeparator);
34293 var v = keys.pop();
34294 if(keys.length > 0){
34295 var f = function(success, node){
34296 if(success && node){
34297 var n = node.findChild(attr, v);
34303 }else if(callback){
34304 callback(false, n);
34308 callback(false, n);
34312 this.expandPath(keys.join(this.pathSeparator), attr, f);
34314 this.root.select();
34316 callback(true, this.root);
34321 getTreeEl : function(){
34326 * Trigger rendering of this TreePanel
34328 render : function(){
34329 if (this.innerCt) {
34330 return this; // stop it rendering more than once!!
34333 this.innerCt = this.el.createChild({tag:"ul",
34334 cls:"x-tree-root-ct " +
34335 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34337 if(this.containerScroll){
34338 Roo.dd.ScrollManager.register(this.el);
34340 if((this.enableDD || this.enableDrop) && !this.dropZone){
34342 * The dropZone used by this tree if drop is enabled
34343 * @type Roo.tree.TreeDropZone
34345 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34346 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34349 if((this.enableDD || this.enableDrag) && !this.dragZone){
34351 * The dragZone used by this tree if drag is enabled
34352 * @type Roo.tree.TreeDragZone
34354 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34355 ddGroup: this.ddGroup || "TreeDD",
34356 scroll: this.ddScroll
34359 this.getSelectionModel().init(this);
34361 Roo.log("ROOT not set in tree");
34364 this.root.render();
34365 if(!this.rootVisible){
34366 this.root.renderChildren();
34372 * Ext JS Library 1.1.1
34373 * Copyright(c) 2006-2007, Ext JS, LLC.
34375 * Originally Released Under LGPL - original licence link has changed is not relivant.
34378 * <script type="text/javascript">
34383 * @class Roo.tree.DefaultSelectionModel
34384 * @extends Roo.util.Observable
34385 * The default single selection for a TreePanel.
34386 * @param {Object} cfg Configuration
34388 Roo.tree.DefaultSelectionModel = function(cfg){
34389 this.selNode = null;
34395 * @event selectionchange
34396 * Fires when the selected node changes
34397 * @param {DefaultSelectionModel} this
34398 * @param {TreeNode} node the new selection
34400 "selectionchange" : true,
34403 * @event beforeselect
34404 * Fires before the selected node changes, return false to cancel the change
34405 * @param {DefaultSelectionModel} this
34406 * @param {TreeNode} node the new selection
34407 * @param {TreeNode} node the old selection
34409 "beforeselect" : true
34412 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34415 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34416 init : function(tree){
34418 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34419 tree.on("click", this.onNodeClick, this);
34422 onNodeClick : function(node, e){
34423 if (e.ctrlKey && this.selNode == node) {
34424 this.unselect(node);
34432 * @param {TreeNode} node The node to select
34433 * @return {TreeNode} The selected node
34435 select : function(node){
34436 var last = this.selNode;
34437 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34439 last.ui.onSelectedChange(false);
34441 this.selNode = node;
34442 node.ui.onSelectedChange(true);
34443 this.fireEvent("selectionchange", this, node, last);
34450 * @param {TreeNode} node The node to unselect
34452 unselect : function(node){
34453 if(this.selNode == node){
34454 this.clearSelections();
34459 * Clear all selections
34461 clearSelections : function(){
34462 var n = this.selNode;
34464 n.ui.onSelectedChange(false);
34465 this.selNode = null;
34466 this.fireEvent("selectionchange", this, null);
34472 * Get the selected node
34473 * @return {TreeNode} The selected node
34475 getSelectedNode : function(){
34476 return this.selNode;
34480 * Returns true if the node is selected
34481 * @param {TreeNode} node The node to check
34482 * @return {Boolean}
34484 isSelected : function(node){
34485 return this.selNode == node;
34489 * Selects the node above the selected node in the tree, intelligently walking the nodes
34490 * @return TreeNode The new selection
34492 selectPrevious : function(){
34493 var s = this.selNode || this.lastSelNode;
34497 var ps = s.previousSibling;
34499 if(!ps.isExpanded() || ps.childNodes.length < 1){
34500 return this.select(ps);
34502 var lc = ps.lastChild;
34503 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34506 return this.select(lc);
34508 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34509 return this.select(s.parentNode);
34515 * Selects the node above the selected node in the tree, intelligently walking the nodes
34516 * @return TreeNode The new selection
34518 selectNext : function(){
34519 var s = this.selNode || this.lastSelNode;
34523 if(s.firstChild && s.isExpanded()){
34524 return this.select(s.firstChild);
34525 }else if(s.nextSibling){
34526 return this.select(s.nextSibling);
34527 }else if(s.parentNode){
34529 s.parentNode.bubble(function(){
34530 if(this.nextSibling){
34531 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34540 onKeyDown : function(e){
34541 var s = this.selNode || this.lastSelNode;
34542 // undesirable, but required
34547 var k = e.getKey();
34555 this.selectPrevious();
34558 e.preventDefault();
34559 if(s.hasChildNodes()){
34560 if(!s.isExpanded()){
34562 }else if(s.firstChild){
34563 this.select(s.firstChild, e);
34568 e.preventDefault();
34569 if(s.hasChildNodes() && s.isExpanded()){
34571 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34572 this.select(s.parentNode, e);
34580 * @class Roo.tree.MultiSelectionModel
34581 * @extends Roo.util.Observable
34582 * Multi selection for a TreePanel.
34583 * @param {Object} cfg Configuration
34585 Roo.tree.MultiSelectionModel = function(){
34586 this.selNodes = [];
34590 * @event selectionchange
34591 * Fires when the selected nodes change
34592 * @param {MultiSelectionModel} this
34593 * @param {Array} nodes Array of the selected nodes
34595 "selectionchange" : true
34597 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34601 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34602 init : function(tree){
34604 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34605 tree.on("click", this.onNodeClick, this);
34608 onNodeClick : function(node, e){
34609 this.select(node, e, e.ctrlKey);
34614 * @param {TreeNode} node The node to select
34615 * @param {EventObject} e (optional) An event associated with the selection
34616 * @param {Boolean} keepExisting True to retain existing selections
34617 * @return {TreeNode} The selected node
34619 select : function(node, e, keepExisting){
34620 if(keepExisting !== true){
34621 this.clearSelections(true);
34623 if(this.isSelected(node)){
34624 this.lastSelNode = node;
34627 this.selNodes.push(node);
34628 this.selMap[node.id] = node;
34629 this.lastSelNode = node;
34630 node.ui.onSelectedChange(true);
34631 this.fireEvent("selectionchange", this, this.selNodes);
34637 * @param {TreeNode} node The node to unselect
34639 unselect : function(node){
34640 if(this.selMap[node.id]){
34641 node.ui.onSelectedChange(false);
34642 var sn = this.selNodes;
34645 index = sn.indexOf(node);
34647 for(var i = 0, len = sn.length; i < len; i++){
34655 this.selNodes.splice(index, 1);
34657 delete this.selMap[node.id];
34658 this.fireEvent("selectionchange", this, this.selNodes);
34663 * Clear all selections
34665 clearSelections : function(suppressEvent){
34666 var sn = this.selNodes;
34668 for(var i = 0, len = sn.length; i < len; i++){
34669 sn[i].ui.onSelectedChange(false);
34671 this.selNodes = [];
34673 if(suppressEvent !== true){
34674 this.fireEvent("selectionchange", this, this.selNodes);
34680 * Returns true if the node is selected
34681 * @param {TreeNode} node The node to check
34682 * @return {Boolean}
34684 isSelected : function(node){
34685 return this.selMap[node.id] ? true : false;
34689 * Returns an array of the selected nodes
34692 getSelectedNodes : function(){
34693 return this.selNodes;
34696 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34698 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34700 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34703 * Ext JS Library 1.1.1
34704 * Copyright(c) 2006-2007, Ext JS, LLC.
34706 * Originally Released Under LGPL - original licence link has changed is not relivant.
34709 * <script type="text/javascript">
34713 * @class Roo.tree.TreeNode
34714 * @extends Roo.data.Node
34715 * @cfg {String} text The text for this node
34716 * @cfg {Boolean} expanded true to start the node expanded
34717 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34718 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34719 * @cfg {Boolean} disabled true to start the node disabled
34720 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34721 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34722 * @cfg {String} cls A css class to be added to the node
34723 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34724 * @cfg {String} href URL of the link used for the node (defaults to #)
34725 * @cfg {String} hrefTarget target frame for the link
34726 * @cfg {String} qtip An Ext QuickTip for the node
34727 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34728 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34729 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34730 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34731 * (defaults to undefined with no checkbox rendered)
34733 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34735 Roo.tree.TreeNode = function(attributes){
34736 attributes = attributes || {};
34737 if(typeof attributes == "string"){
34738 attributes = {text: attributes};
34740 this.childrenRendered = false;
34741 this.rendered = false;
34742 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34743 this.expanded = attributes.expanded === true;
34744 this.isTarget = attributes.isTarget !== false;
34745 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34746 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34749 * Read-only. The text for this node. To change it use setText().
34752 this.text = attributes.text;
34754 * True if this node is disabled.
34757 this.disabled = attributes.disabled === true;
34761 * @event textchange
34762 * Fires when the text for this node is changed
34763 * @param {Node} this This node
34764 * @param {String} text The new text
34765 * @param {String} oldText The old text
34767 "textchange" : true,
34769 * @event beforeexpand
34770 * Fires before this node is expanded, return false to cancel.
34771 * @param {Node} this This node
34772 * @param {Boolean} deep
34773 * @param {Boolean} anim
34775 "beforeexpand" : true,
34777 * @event beforecollapse
34778 * Fires before this node is collapsed, return false to cancel.
34779 * @param {Node} this This node
34780 * @param {Boolean} deep
34781 * @param {Boolean} anim
34783 "beforecollapse" : true,
34786 * Fires when this node is expanded
34787 * @param {Node} this This node
34791 * @event disabledchange
34792 * Fires when the disabled status of this node changes
34793 * @param {Node} this This node
34794 * @param {Boolean} disabled
34796 "disabledchange" : true,
34799 * Fires when this node is collapsed
34800 * @param {Node} this This node
34804 * @event beforeclick
34805 * Fires before click processing. Return false to cancel the default action.
34806 * @param {Node} this This node
34807 * @param {Roo.EventObject} e The event object
34809 "beforeclick":true,
34811 * @event checkchange
34812 * Fires when a node with a checkbox's checked property changes
34813 * @param {Node} this This node
34814 * @param {Boolean} checked
34816 "checkchange":true,
34819 * Fires when this node is clicked
34820 * @param {Node} this This node
34821 * @param {Roo.EventObject} e The event object
34826 * Fires when this node is double clicked
34827 * @param {Node} this This node
34828 * @param {Roo.EventObject} e The event object
34832 * @event contextmenu
34833 * Fires when this node is right clicked
34834 * @param {Node} this This node
34835 * @param {Roo.EventObject} e The event object
34837 "contextmenu":true,
34839 * @event beforechildrenrendered
34840 * Fires right before the child nodes for this node are rendered
34841 * @param {Node} this This node
34843 "beforechildrenrendered":true
34846 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34849 * Read-only. The UI for this node
34852 this.ui = new uiClass(this);
34854 // finally support items[]
34855 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34860 Roo.each(this.attributes.items, function(c) {
34861 this.appendChild(Roo.factory(c,Roo.Tree));
34863 delete this.attributes.items;
34868 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34869 preventHScroll: true,
34871 * Returns true if this node is expanded
34872 * @return {Boolean}
34874 isExpanded : function(){
34875 return this.expanded;
34879 * Returns the UI object for this node
34880 * @return {TreeNodeUI}
34882 getUI : function(){
34886 // private override
34887 setFirstChild : function(node){
34888 var of = this.firstChild;
34889 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34890 if(this.childrenRendered && of && node != of){
34891 of.renderIndent(true, true);
34894 this.renderIndent(true, true);
34898 // private override
34899 setLastChild : function(node){
34900 var ol = this.lastChild;
34901 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34902 if(this.childrenRendered && ol && node != ol){
34903 ol.renderIndent(true, true);
34906 this.renderIndent(true, true);
34910 // these methods are overridden to provide lazy rendering support
34911 // private override
34912 appendChild : function()
34914 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34915 if(node && this.childrenRendered){
34918 this.ui.updateExpandIcon();
34922 // private override
34923 removeChild : function(node){
34924 this.ownerTree.getSelectionModel().unselect(node);
34925 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34926 // if it's been rendered remove dom node
34927 if(this.childrenRendered){
34930 if(this.childNodes.length < 1){
34931 this.collapse(false, false);
34933 this.ui.updateExpandIcon();
34935 if(!this.firstChild) {
34936 this.childrenRendered = false;
34941 // private override
34942 insertBefore : function(node, refNode){
34943 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34944 if(newNode && refNode && this.childrenRendered){
34947 this.ui.updateExpandIcon();
34952 * Sets the text for this node
34953 * @param {String} text
34955 setText : function(text){
34956 var oldText = this.text;
34958 this.attributes.text = text;
34959 if(this.rendered){ // event without subscribing
34960 this.ui.onTextChange(this, text, oldText);
34962 this.fireEvent("textchange", this, text, oldText);
34966 * Triggers selection of this node
34968 select : function(){
34969 this.getOwnerTree().getSelectionModel().select(this);
34973 * Triggers deselection of this node
34975 unselect : function(){
34976 this.getOwnerTree().getSelectionModel().unselect(this);
34980 * Returns true if this node is selected
34981 * @return {Boolean}
34983 isSelected : function(){
34984 return this.getOwnerTree().getSelectionModel().isSelected(this);
34988 * Expand this node.
34989 * @param {Boolean} deep (optional) True to expand all children as well
34990 * @param {Boolean} anim (optional) false to cancel the default animation
34991 * @param {Function} callback (optional) A callback to be called when
34992 * expanding this node completes (does not wait for deep expand to complete).
34993 * Called with 1 parameter, this node.
34995 expand : function(deep, anim, callback){
34996 if(!this.expanded){
34997 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35000 if(!this.childrenRendered){
35001 this.renderChildren();
35003 this.expanded = true;
35004 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35005 this.ui.animExpand(function(){
35006 this.fireEvent("expand", this);
35007 if(typeof callback == "function"){
35011 this.expandChildNodes(true);
35013 }.createDelegate(this));
35017 this.fireEvent("expand", this);
35018 if(typeof callback == "function"){
35023 if(typeof callback == "function"){
35028 this.expandChildNodes(true);
35032 isHiddenRoot : function(){
35033 return this.isRoot && !this.getOwnerTree().rootVisible;
35037 * Collapse this node.
35038 * @param {Boolean} deep (optional) True to collapse all children as well
35039 * @param {Boolean} anim (optional) false to cancel the default animation
35041 collapse : function(deep, anim){
35042 if(this.expanded && !this.isHiddenRoot()){
35043 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35046 this.expanded = false;
35047 if((this.getOwnerTree().animate && anim !== false) || anim){
35048 this.ui.animCollapse(function(){
35049 this.fireEvent("collapse", this);
35051 this.collapseChildNodes(true);
35053 }.createDelegate(this));
35056 this.ui.collapse();
35057 this.fireEvent("collapse", this);
35061 var cs = this.childNodes;
35062 for(var i = 0, len = cs.length; i < len; i++) {
35063 cs[i].collapse(true, false);
35069 delayedExpand : function(delay){
35070 if(!this.expandProcId){
35071 this.expandProcId = this.expand.defer(delay, this);
35076 cancelExpand : function(){
35077 if(this.expandProcId){
35078 clearTimeout(this.expandProcId);
35080 this.expandProcId = false;
35084 * Toggles expanded/collapsed state of the node
35086 toggle : function(){
35095 * Ensures all parent nodes are expanded
35097 ensureVisible : function(callback){
35098 var tree = this.getOwnerTree();
35099 tree.expandPath(this.parentNode.getPath(), false, function(){
35100 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35101 Roo.callback(callback);
35102 }.createDelegate(this));
35106 * Expand all child nodes
35107 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35109 expandChildNodes : function(deep){
35110 var cs = this.childNodes;
35111 for(var i = 0, len = cs.length; i < len; i++) {
35112 cs[i].expand(deep);
35117 * Collapse all child nodes
35118 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35120 collapseChildNodes : function(deep){
35121 var cs = this.childNodes;
35122 for(var i = 0, len = cs.length; i < len; i++) {
35123 cs[i].collapse(deep);
35128 * Disables this node
35130 disable : function(){
35131 this.disabled = true;
35133 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35134 this.ui.onDisableChange(this, true);
35136 this.fireEvent("disabledchange", this, true);
35140 * Enables this node
35142 enable : function(){
35143 this.disabled = false;
35144 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35145 this.ui.onDisableChange(this, false);
35147 this.fireEvent("disabledchange", this, false);
35151 renderChildren : function(suppressEvent){
35152 if(suppressEvent !== false){
35153 this.fireEvent("beforechildrenrendered", this);
35155 var cs = this.childNodes;
35156 for(var i = 0, len = cs.length; i < len; i++){
35157 cs[i].render(true);
35159 this.childrenRendered = true;
35163 sort : function(fn, scope){
35164 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35165 if(this.childrenRendered){
35166 var cs = this.childNodes;
35167 for(var i = 0, len = cs.length; i < len; i++){
35168 cs[i].render(true);
35174 render : function(bulkRender){
35175 this.ui.render(bulkRender);
35176 if(!this.rendered){
35177 this.rendered = true;
35179 this.expanded = false;
35180 this.expand(false, false);
35186 renderIndent : function(deep, refresh){
35188 this.ui.childIndent = null;
35190 this.ui.renderIndent();
35191 if(deep === true && this.childrenRendered){
35192 var cs = this.childNodes;
35193 for(var i = 0, len = cs.length; i < len; i++){
35194 cs[i].renderIndent(true, refresh);
35200 * Ext JS Library 1.1.1
35201 * Copyright(c) 2006-2007, Ext JS, LLC.
35203 * Originally Released Under LGPL - original licence link has changed is not relivant.
35206 * <script type="text/javascript">
35210 * @class Roo.tree.AsyncTreeNode
35211 * @extends Roo.tree.TreeNode
35212 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35214 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35216 Roo.tree.AsyncTreeNode = function(config){
35217 this.loaded = false;
35218 this.loading = false;
35219 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35221 * @event beforeload
35222 * Fires before this node is loaded, return false to cancel
35223 * @param {Node} this This node
35225 this.addEvents({'beforeload':true, 'load': true});
35228 * Fires when this node is loaded
35229 * @param {Node} this This node
35232 * The loader used by this node (defaults to using the tree's defined loader)
35237 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35238 expand : function(deep, anim, callback){
35239 if(this.loading){ // if an async load is already running, waiting til it's done
35241 var f = function(){
35242 if(!this.loading){ // done loading
35243 clearInterval(timer);
35244 this.expand(deep, anim, callback);
35246 }.createDelegate(this);
35247 timer = setInterval(f, 200);
35251 if(this.fireEvent("beforeload", this) === false){
35254 this.loading = true;
35255 this.ui.beforeLoad(this);
35256 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35258 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35262 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35266 * Returns true if this node is currently loading
35267 * @return {Boolean}
35269 isLoading : function(){
35270 return this.loading;
35273 loadComplete : function(deep, anim, callback){
35274 this.loading = false;
35275 this.loaded = true;
35276 this.ui.afterLoad(this);
35277 this.fireEvent("load", this);
35278 this.expand(deep, anim, callback);
35282 * Returns true if this node has been loaded
35283 * @return {Boolean}
35285 isLoaded : function(){
35286 return this.loaded;
35289 hasChildNodes : function(){
35290 if(!this.isLeaf() && !this.loaded){
35293 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35298 * Trigger a reload for this node
35299 * @param {Function} callback
35301 reload : function(callback){
35302 this.collapse(false, false);
35303 while(this.firstChild){
35304 this.removeChild(this.firstChild);
35306 this.childrenRendered = false;
35307 this.loaded = false;
35308 if(this.isHiddenRoot()){
35309 this.expanded = false;
35311 this.expand(false, false, callback);
35315 * Ext JS Library 1.1.1
35316 * Copyright(c) 2006-2007, Ext JS, LLC.
35318 * Originally Released Under LGPL - original licence link has changed is not relivant.
35321 * <script type="text/javascript">
35325 * @class Roo.tree.TreeNodeUI
35327 * @param {Object} node The node to render
35328 * The TreeNode UI implementation is separate from the
35329 * tree implementation. Unless you are customizing the tree UI,
35330 * you should never have to use this directly.
35332 Roo.tree.TreeNodeUI = function(node){
35334 this.rendered = false;
35335 this.animating = false;
35336 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35339 Roo.tree.TreeNodeUI.prototype = {
35340 removeChild : function(node){
35342 this.ctNode.removeChild(node.ui.getEl());
35346 beforeLoad : function(){
35347 this.addClass("x-tree-node-loading");
35350 afterLoad : function(){
35351 this.removeClass("x-tree-node-loading");
35354 onTextChange : function(node, text, oldText){
35356 this.textNode.innerHTML = text;
35360 onDisableChange : function(node, state){
35361 this.disabled = state;
35363 this.addClass("x-tree-node-disabled");
35365 this.removeClass("x-tree-node-disabled");
35369 onSelectedChange : function(state){
35372 this.addClass("x-tree-selected");
35375 this.removeClass("x-tree-selected");
35379 onMove : function(tree, node, oldParent, newParent, index, refNode){
35380 this.childIndent = null;
35382 var targetNode = newParent.ui.getContainer();
35383 if(!targetNode){//target not rendered
35384 this.holder = document.createElement("div");
35385 this.holder.appendChild(this.wrap);
35388 var insertBefore = refNode ? refNode.ui.getEl() : null;
35390 targetNode.insertBefore(this.wrap, insertBefore);
35392 targetNode.appendChild(this.wrap);
35394 this.node.renderIndent(true);
35398 addClass : function(cls){
35400 Roo.fly(this.elNode).addClass(cls);
35404 removeClass : function(cls){
35406 Roo.fly(this.elNode).removeClass(cls);
35410 remove : function(){
35412 this.holder = document.createElement("div");
35413 this.holder.appendChild(this.wrap);
35417 fireEvent : function(){
35418 return this.node.fireEvent.apply(this.node, arguments);
35421 initEvents : function(){
35422 this.node.on("move", this.onMove, this);
35423 var E = Roo.EventManager;
35424 var a = this.anchor;
35426 var el = Roo.fly(a, '_treeui');
35428 if(Roo.isOpera){ // opera render bug ignores the CSS
35429 el.setStyle("text-decoration", "none");
35432 el.on("click", this.onClick, this);
35433 el.on("dblclick", this.onDblClick, this);
35436 Roo.EventManager.on(this.checkbox,
35437 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35440 el.on("contextmenu", this.onContextMenu, this);
35442 var icon = Roo.fly(this.iconNode);
35443 icon.on("click", this.onClick, this);
35444 icon.on("dblclick", this.onDblClick, this);
35445 icon.on("contextmenu", this.onContextMenu, this);
35446 E.on(this.ecNode, "click", this.ecClick, this, true);
35448 if(this.node.disabled){
35449 this.addClass("x-tree-node-disabled");
35451 if(this.node.hidden){
35452 this.addClass("x-tree-node-disabled");
35454 var ot = this.node.getOwnerTree();
35455 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35456 if(dd && (!this.node.isRoot || ot.rootVisible)){
35457 Roo.dd.Registry.register(this.elNode, {
35459 handles: this.getDDHandles(),
35465 getDDHandles : function(){
35466 return [this.iconNode, this.textNode];
35471 this.wrap.style.display = "none";
35477 this.wrap.style.display = "";
35481 onContextMenu : function(e){
35482 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35483 e.preventDefault();
35485 this.fireEvent("contextmenu", this.node, e);
35489 onClick : function(e){
35494 if(this.fireEvent("beforeclick", this.node, e) !== false){
35495 if(!this.disabled && this.node.attributes.href){
35496 this.fireEvent("click", this.node, e);
35499 e.preventDefault();
35504 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35505 this.node.toggle();
35508 this.fireEvent("click", this.node, e);
35514 onDblClick : function(e){
35515 e.preventDefault();
35520 this.toggleCheck();
35522 if(!this.animating && this.node.hasChildNodes()){
35523 this.node.toggle();
35525 this.fireEvent("dblclick", this.node, e);
35528 onCheckChange : function(){
35529 var checked = this.checkbox.checked;
35530 this.node.attributes.checked = checked;
35531 this.fireEvent('checkchange', this.node, checked);
35534 ecClick : function(e){
35535 if(!this.animating && this.node.hasChildNodes()){
35536 this.node.toggle();
35540 startDrop : function(){
35541 this.dropping = true;
35544 // delayed drop so the click event doesn't get fired on a drop
35545 endDrop : function(){
35546 setTimeout(function(){
35547 this.dropping = false;
35548 }.createDelegate(this), 50);
35551 expand : function(){
35552 this.updateExpandIcon();
35553 this.ctNode.style.display = "";
35556 focus : function(){
35557 if(!this.node.preventHScroll){
35558 try{this.anchor.focus();
35560 }else if(!Roo.isIE){
35562 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35563 var l = noscroll.scrollLeft;
35564 this.anchor.focus();
35565 noscroll.scrollLeft = l;
35570 toggleCheck : function(value){
35571 var cb = this.checkbox;
35573 cb.checked = (value === undefined ? !cb.checked : value);
35579 this.anchor.blur();
35583 animExpand : function(callback){
35584 var ct = Roo.get(this.ctNode);
35586 if(!this.node.hasChildNodes()){
35587 this.updateExpandIcon();
35588 this.ctNode.style.display = "";
35589 Roo.callback(callback);
35592 this.animating = true;
35593 this.updateExpandIcon();
35596 callback : function(){
35597 this.animating = false;
35598 Roo.callback(callback);
35601 duration: this.node.ownerTree.duration || .25
35605 highlight : function(){
35606 var tree = this.node.getOwnerTree();
35607 Roo.fly(this.wrap).highlight(
35608 tree.hlColor || "C3DAF9",
35609 {endColor: tree.hlBaseColor}
35613 collapse : function(){
35614 this.updateExpandIcon();
35615 this.ctNode.style.display = "none";
35618 animCollapse : function(callback){
35619 var ct = Roo.get(this.ctNode);
35620 ct.enableDisplayMode('block');
35623 this.animating = true;
35624 this.updateExpandIcon();
35627 callback : function(){
35628 this.animating = false;
35629 Roo.callback(callback);
35632 duration: this.node.ownerTree.duration || .25
35636 getContainer : function(){
35637 return this.ctNode;
35640 getEl : function(){
35644 appendDDGhost : function(ghostNode){
35645 ghostNode.appendChild(this.elNode.cloneNode(true));
35648 getDDRepairXY : function(){
35649 return Roo.lib.Dom.getXY(this.iconNode);
35652 onRender : function(){
35656 render : function(bulkRender){
35657 var n = this.node, a = n.attributes;
35658 var targetNode = n.parentNode ?
35659 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35661 if(!this.rendered){
35662 this.rendered = true;
35664 this.renderElements(n, a, targetNode, bulkRender);
35667 if(this.textNode.setAttributeNS){
35668 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35670 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35673 this.textNode.setAttribute("ext:qtip", a.qtip);
35675 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35678 }else if(a.qtipCfg){
35679 a.qtipCfg.target = Roo.id(this.textNode);
35680 Roo.QuickTips.register(a.qtipCfg);
35683 if(!this.node.expanded){
35684 this.updateExpandIcon();
35687 if(bulkRender === true) {
35688 targetNode.appendChild(this.wrap);
35693 renderElements : function(n, a, targetNode, bulkRender)
35695 // add some indent caching, this helps performance when rendering a large tree
35696 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35697 var t = n.getOwnerTree();
35698 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35699 if (typeof(n.attributes.html) != 'undefined') {
35700 txt = n.attributes.html;
35702 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35703 var cb = typeof a.checked == 'boolean';
35704 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35705 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35706 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35707 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35708 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35709 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35710 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35711 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35712 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35713 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35716 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35717 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35718 n.nextSibling.ui.getEl(), buf.join(""));
35720 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35723 this.elNode = this.wrap.childNodes[0];
35724 this.ctNode = this.wrap.childNodes[1];
35725 var cs = this.elNode.childNodes;
35726 this.indentNode = cs[0];
35727 this.ecNode = cs[1];
35728 this.iconNode = cs[2];
35731 this.checkbox = cs[3];
35734 this.anchor = cs[index];
35735 this.textNode = cs[index].firstChild;
35738 getAnchor : function(){
35739 return this.anchor;
35742 getTextEl : function(){
35743 return this.textNode;
35746 getIconEl : function(){
35747 return this.iconNode;
35750 isChecked : function(){
35751 return this.checkbox ? this.checkbox.checked : false;
35754 updateExpandIcon : function(){
35756 var n = this.node, c1, c2;
35757 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35758 var hasChild = n.hasChildNodes();
35762 c1 = "x-tree-node-collapsed";
35763 c2 = "x-tree-node-expanded";
35766 c1 = "x-tree-node-expanded";
35767 c2 = "x-tree-node-collapsed";
35770 this.removeClass("x-tree-node-leaf");
35771 this.wasLeaf = false;
35773 if(this.c1 != c1 || this.c2 != c2){
35774 Roo.fly(this.elNode).replaceClass(c1, c2);
35775 this.c1 = c1; this.c2 = c2;
35778 // this changes non-leafs into leafs if they have no children.
35779 // it's not very rational behaviour..
35781 if(!this.wasLeaf && this.node.leaf){
35782 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35785 this.wasLeaf = true;
35788 var ecc = "x-tree-ec-icon "+cls;
35789 if(this.ecc != ecc){
35790 this.ecNode.className = ecc;
35796 getChildIndent : function(){
35797 if(!this.childIndent){
35801 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35803 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35805 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35810 this.childIndent = buf.join("");
35812 return this.childIndent;
35815 renderIndent : function(){
35818 var p = this.node.parentNode;
35820 indent = p.ui.getChildIndent();
35822 if(this.indentMarkup != indent){ // don't rerender if not required
35823 this.indentNode.innerHTML = indent;
35824 this.indentMarkup = indent;
35826 this.updateExpandIcon();
35831 Roo.tree.RootTreeNodeUI = function(){
35832 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35834 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35835 render : function(){
35836 if(!this.rendered){
35837 var targetNode = this.node.ownerTree.innerCt.dom;
35838 this.node.expanded = true;
35839 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35840 this.wrap = this.ctNode = targetNode.firstChild;
35843 collapse : function(){
35845 expand : function(){
35849 * Ext JS Library 1.1.1
35850 * Copyright(c) 2006-2007, Ext JS, LLC.
35852 * Originally Released Under LGPL - original licence link has changed is not relivant.
35855 * <script type="text/javascript">
35858 * @class Roo.tree.TreeLoader
35859 * @extends Roo.util.Observable
35860 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35861 * nodes from a specified URL. The response must be a javascript Array definition
35862 * who's elements are node definition objects. eg:
35867 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35868 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35875 * The old style respose with just an array is still supported, but not recommended.
35878 * A server request is sent, and child nodes are loaded only when a node is expanded.
35879 * The loading node's id is passed to the server under the parameter name "node" to
35880 * enable the server to produce the correct child nodes.
35882 * To pass extra parameters, an event handler may be attached to the "beforeload"
35883 * event, and the parameters specified in the TreeLoader's baseParams property:
35885 myTreeLoader.on("beforeload", function(treeLoader, node) {
35886 this.baseParams.category = node.attributes.category;
35889 * This would pass an HTTP parameter called "category" to the server containing
35890 * the value of the Node's "category" attribute.
35892 * Creates a new Treeloader.
35893 * @param {Object} config A config object containing config properties.
35895 Roo.tree.TreeLoader = function(config){
35896 this.baseParams = {};
35897 this.requestMethod = "POST";
35898 Roo.apply(this, config);
35903 * @event beforeload
35904 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35905 * @param {Object} This TreeLoader object.
35906 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35907 * @param {Object} callback The callback function specified in the {@link #load} call.
35912 * Fires when the node has been successfuly loaded.
35913 * @param {Object} This TreeLoader object.
35914 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35915 * @param {Object} response The response object containing the data from the server.
35919 * @event loadexception
35920 * Fires if the network request failed.
35921 * @param {Object} This TreeLoader object.
35922 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35923 * @param {Object} response The response object containing the data from the server.
35925 loadexception : true,
35928 * Fires before a node is created, enabling you to return custom Node types
35929 * @param {Object} This TreeLoader object.
35930 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35935 Roo.tree.TreeLoader.superclass.constructor.call(this);
35938 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35940 * @cfg {String} dataUrl The URL from which to request a Json string which
35941 * specifies an array of node definition object representing the child nodes
35945 * @cfg {String} requestMethod either GET or POST
35946 * defaults to POST (due to BC)
35950 * @cfg {Object} baseParams (optional) An object containing properties which
35951 * specify HTTP parameters to be passed to each request for child nodes.
35954 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35955 * created by this loader. If the attributes sent by the server have an attribute in this object,
35956 * they take priority.
35959 * @cfg {Object} uiProviders (optional) An object containing properties which
35961 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35962 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35963 * <i>uiProvider</i> attribute of a returned child node is a string rather
35964 * than a reference to a TreeNodeUI implementation, this that string value
35965 * is used as a property name in the uiProviders object. You can define the provider named
35966 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35971 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35972 * child nodes before loading.
35974 clearOnLoad : true,
35977 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35978 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35979 * Grid query { data : [ .....] }
35984 * @cfg {String} queryParam (optional)
35985 * Name of the query as it will be passed on the querystring (defaults to 'node')
35986 * eg. the request will be ?node=[id]
35993 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35994 * This is called automatically when a node is expanded, but may be used to reload
35995 * a node (or append new children if the {@link #clearOnLoad} option is false.)
35996 * @param {Roo.tree.TreeNode} node
35997 * @param {Function} callback
35999 load : function(node, callback){
36000 if(this.clearOnLoad){
36001 while(node.firstChild){
36002 node.removeChild(node.firstChild);
36005 if(node.attributes.children){ // preloaded json children
36006 var cs = node.attributes.children;
36007 for(var i = 0, len = cs.length; i < len; i++){
36008 node.appendChild(this.createNode(cs[i]));
36010 if(typeof callback == "function"){
36013 }else if(this.dataUrl){
36014 this.requestData(node, callback);
36018 getParams: function(node){
36019 var buf = [], bp = this.baseParams;
36020 for(var key in bp){
36021 if(typeof bp[key] != "function"){
36022 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36025 var n = this.queryParam === false ? 'node' : this.queryParam;
36026 buf.push(n + "=", encodeURIComponent(node.id));
36027 return buf.join("");
36030 requestData : function(node, callback){
36031 if(this.fireEvent("beforeload", this, node, callback) !== false){
36032 this.transId = Roo.Ajax.request({
36033 method:this.requestMethod,
36034 url: this.dataUrl||this.url,
36035 success: this.handleResponse,
36036 failure: this.handleFailure,
36038 argument: {callback: callback, node: node},
36039 params: this.getParams(node)
36042 // if the load is cancelled, make sure we notify
36043 // the node that we are done
36044 if(typeof callback == "function"){
36050 isLoading : function(){
36051 return this.transId ? true : false;
36054 abort : function(){
36055 if(this.isLoading()){
36056 Roo.Ajax.abort(this.transId);
36061 createNode : function(attr)
36063 // apply baseAttrs, nice idea Corey!
36064 if(this.baseAttrs){
36065 Roo.applyIf(attr, this.baseAttrs);
36067 if(this.applyLoader !== false){
36068 attr.loader = this;
36070 // uiProvider = depreciated..
36072 if(typeof(attr.uiProvider) == 'string'){
36073 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36074 /** eval:var:attr */ eval(attr.uiProvider);
36076 if(typeof(this.uiProviders['default']) != 'undefined') {
36077 attr.uiProvider = this.uiProviders['default'];
36080 this.fireEvent('create', this, attr);
36082 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36084 new Roo.tree.TreeNode(attr) :
36085 new Roo.tree.AsyncTreeNode(attr));
36088 processResponse : function(response, node, callback)
36090 var json = response.responseText;
36093 var o = Roo.decode(json);
36095 if (this.root === false && typeof(o.success) != undefined) {
36096 this.root = 'data'; // the default behaviour for list like data..
36099 if (this.root !== false && !o.success) {
36100 // it's a failure condition.
36101 var a = response.argument;
36102 this.fireEvent("loadexception", this, a.node, response);
36103 Roo.log("Load failed - should have a handler really");
36109 if (this.root !== false) {
36113 for(var i = 0, len = o.length; i < len; i++){
36114 var n = this.createNode(o[i]);
36116 node.appendChild(n);
36119 if(typeof callback == "function"){
36120 callback(this, node);
36123 this.handleFailure(response);
36127 handleResponse : function(response){
36128 this.transId = false;
36129 var a = response.argument;
36130 this.processResponse(response, a.node, a.callback);
36131 this.fireEvent("load", this, a.node, response);
36134 handleFailure : function(response)
36136 // should handle failure better..
36137 this.transId = false;
36138 var a = response.argument;
36139 this.fireEvent("loadexception", this, a.node, response);
36140 if(typeof a.callback == "function"){
36141 a.callback(this, a.node);
36146 * Ext JS Library 1.1.1
36147 * Copyright(c) 2006-2007, Ext JS, LLC.
36149 * Originally Released Under LGPL - original licence link has changed is not relivant.
36152 * <script type="text/javascript">
36156 * @class Roo.tree.TreeFilter
36157 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36158 * @param {TreePanel} tree
36159 * @param {Object} config (optional)
36161 Roo.tree.TreeFilter = function(tree, config){
36163 this.filtered = {};
36164 Roo.apply(this, config);
36167 Roo.tree.TreeFilter.prototype = {
36174 * Filter the data by a specific attribute.
36175 * @param {String/RegExp} value Either string that the attribute value
36176 * should start with or a RegExp to test against the attribute
36177 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36178 * @param {TreeNode} startNode (optional) The node to start the filter at.
36180 filter : function(value, attr, startNode){
36181 attr = attr || "text";
36183 if(typeof value == "string"){
36184 var vlen = value.length;
36185 // auto clear empty filter
36186 if(vlen == 0 && this.clearBlank){
36190 value = value.toLowerCase();
36192 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36194 }else if(value.exec){ // regex?
36196 return value.test(n.attributes[attr]);
36199 throw 'Illegal filter type, must be string or regex';
36201 this.filterBy(f, null, startNode);
36205 * Filter by a function. The passed function will be called with each
36206 * node in the tree (or from the startNode). If the function returns true, the node is kept
36207 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36208 * @param {Function} fn The filter function
36209 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36211 filterBy : function(fn, scope, startNode){
36212 startNode = startNode || this.tree.root;
36213 if(this.autoClear){
36216 var af = this.filtered, rv = this.reverse;
36217 var f = function(n){
36218 if(n == startNode){
36224 var m = fn.call(scope || n, n);
36232 startNode.cascade(f);
36235 if(typeof id != "function"){
36237 if(n && n.parentNode){
36238 n.parentNode.removeChild(n);
36246 * Clears the current filter. Note: with the "remove" option
36247 * set a filter cannot be cleared.
36249 clear : function(){
36251 var af = this.filtered;
36253 if(typeof id != "function"){
36260 this.filtered = {};
36265 * Ext JS Library 1.1.1
36266 * Copyright(c) 2006-2007, Ext JS, LLC.
36268 * Originally Released Under LGPL - original licence link has changed is not relivant.
36271 * <script type="text/javascript">
36276 * @class Roo.tree.TreeSorter
36277 * Provides sorting of nodes in a TreePanel
36279 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36280 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36281 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36282 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36283 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36284 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36286 * @param {TreePanel} tree
36287 * @param {Object} config
36289 Roo.tree.TreeSorter = function(tree, config){
36290 Roo.apply(this, config);
36291 tree.on("beforechildrenrendered", this.doSort, this);
36292 tree.on("append", this.updateSort, this);
36293 tree.on("insert", this.updateSort, this);
36295 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36296 var p = this.property || "text";
36297 var sortType = this.sortType;
36298 var fs = this.folderSort;
36299 var cs = this.caseSensitive === true;
36300 var leafAttr = this.leafAttr || 'leaf';
36302 this.sortFn = function(n1, n2){
36304 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36307 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36311 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36312 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36314 return dsc ? +1 : -1;
36316 return dsc ? -1 : +1;
36323 Roo.tree.TreeSorter.prototype = {
36324 doSort : function(node){
36325 node.sort(this.sortFn);
36328 compareNodes : function(n1, n2){
36329 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36332 updateSort : function(tree, node){
36333 if(node.childrenRendered){
36334 this.doSort.defer(1, this, [node]);
36339 * Ext JS Library 1.1.1
36340 * Copyright(c) 2006-2007, Ext JS, LLC.
36342 * Originally Released Under LGPL - original licence link has changed is not relivant.
36345 * <script type="text/javascript">
36348 if(Roo.dd.DropZone){
36350 Roo.tree.TreeDropZone = function(tree, config){
36351 this.allowParentInsert = false;
36352 this.allowContainerDrop = false;
36353 this.appendOnly = false;
36354 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36356 this.lastInsertClass = "x-tree-no-status";
36357 this.dragOverData = {};
36360 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36361 ddGroup : "TreeDD",
36364 expandDelay : 1000,
36366 expandNode : function(node){
36367 if(node.hasChildNodes() && !node.isExpanded()){
36368 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36372 queueExpand : function(node){
36373 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36376 cancelExpand : function(){
36377 if(this.expandProcId){
36378 clearTimeout(this.expandProcId);
36379 this.expandProcId = false;
36383 isValidDropPoint : function(n, pt, dd, e, data){
36384 if(!n || !data){ return false; }
36385 var targetNode = n.node;
36386 var dropNode = data.node;
36387 // default drop rules
36388 if(!(targetNode && targetNode.isTarget && pt)){
36391 if(pt == "append" && targetNode.allowChildren === false){
36394 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36397 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36400 // reuse the object
36401 var overEvent = this.dragOverData;
36402 overEvent.tree = this.tree;
36403 overEvent.target = targetNode;
36404 overEvent.data = data;
36405 overEvent.point = pt;
36406 overEvent.source = dd;
36407 overEvent.rawEvent = e;
36408 overEvent.dropNode = dropNode;
36409 overEvent.cancel = false;
36410 var result = this.tree.fireEvent("nodedragover", overEvent);
36411 return overEvent.cancel === false && result !== false;
36414 getDropPoint : function(e, n, dd)
36418 return tn.allowChildren !== false ? "append" : false; // always append for root
36420 var dragEl = n.ddel;
36421 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36422 var y = Roo.lib.Event.getPageY(e);
36423 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36425 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36426 var noAppend = tn.allowChildren === false;
36427 if(this.appendOnly || tn.parentNode.allowChildren === false){
36428 return noAppend ? false : "append";
36430 var noBelow = false;
36431 if(!this.allowParentInsert){
36432 noBelow = tn.hasChildNodes() && tn.isExpanded();
36434 var q = (b - t) / (noAppend ? 2 : 3);
36435 if(y >= t && y < (t + q)){
36437 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36444 onNodeEnter : function(n, dd, e, data)
36446 this.cancelExpand();
36449 onNodeOver : function(n, dd, e, data)
36452 var pt = this.getDropPoint(e, n, dd);
36455 // auto node expand check
36456 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36457 this.queueExpand(node);
36458 }else if(pt != "append"){
36459 this.cancelExpand();
36462 // set the insert point style on the target node
36463 var returnCls = this.dropNotAllowed;
36464 if(this.isValidDropPoint(n, pt, dd, e, data)){
36469 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36470 cls = "x-tree-drag-insert-above";
36471 }else if(pt == "below"){
36472 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36473 cls = "x-tree-drag-insert-below";
36475 returnCls = "x-tree-drop-ok-append";
36476 cls = "x-tree-drag-append";
36478 if(this.lastInsertClass != cls){
36479 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36480 this.lastInsertClass = cls;
36487 onNodeOut : function(n, dd, e, data){
36489 this.cancelExpand();
36490 this.removeDropIndicators(n);
36493 onNodeDrop : function(n, dd, e, data){
36494 var point = this.getDropPoint(e, n, dd);
36495 var targetNode = n.node;
36496 targetNode.ui.startDrop();
36497 if(!this.isValidDropPoint(n, point, dd, e, data)){
36498 targetNode.ui.endDrop();
36501 // first try to find the drop node
36502 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36505 target: targetNode,
36510 dropNode: dropNode,
36513 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36514 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36515 targetNode.ui.endDrop();
36518 // allow target changing
36519 targetNode = dropEvent.target;
36520 if(point == "append" && !targetNode.isExpanded()){
36521 targetNode.expand(false, null, function(){
36522 this.completeDrop(dropEvent);
36523 }.createDelegate(this));
36525 this.completeDrop(dropEvent);
36530 completeDrop : function(de){
36531 var ns = de.dropNode, p = de.point, t = de.target;
36532 if(!(ns instanceof Array)){
36536 for(var i = 0, len = ns.length; i < len; i++){
36539 t.parentNode.insertBefore(n, t);
36540 }else if(p == "below"){
36541 t.parentNode.insertBefore(n, t.nextSibling);
36547 if(this.tree.hlDrop){
36551 this.tree.fireEvent("nodedrop", de);
36554 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36555 if(this.tree.hlDrop){
36556 dropNode.ui.focus();
36557 dropNode.ui.highlight();
36559 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36562 getTree : function(){
36566 removeDropIndicators : function(n){
36569 Roo.fly(el).removeClass([
36570 "x-tree-drag-insert-above",
36571 "x-tree-drag-insert-below",
36572 "x-tree-drag-append"]);
36573 this.lastInsertClass = "_noclass";
36577 beforeDragDrop : function(target, e, id){
36578 this.cancelExpand();
36582 afterRepair : function(data){
36583 if(data && Roo.enableFx){
36584 data.node.ui.highlight();
36594 * Ext JS Library 1.1.1
36595 * Copyright(c) 2006-2007, Ext JS, LLC.
36597 * Originally Released Under LGPL - original licence link has changed is not relivant.
36600 * <script type="text/javascript">
36604 if(Roo.dd.DragZone){
36605 Roo.tree.TreeDragZone = function(tree, config){
36606 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36610 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36611 ddGroup : "TreeDD",
36613 onBeforeDrag : function(data, e){
36615 return n && n.draggable && !n.disabled;
36619 onInitDrag : function(e){
36620 var data = this.dragData;
36621 this.tree.getSelectionModel().select(data.node);
36622 this.proxy.update("");
36623 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36624 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36627 getRepairXY : function(e, data){
36628 return data.node.ui.getDDRepairXY();
36631 onEndDrag : function(data, e){
36632 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36637 onValidDrop : function(dd, e, id){
36638 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36642 beforeInvalidDrop : function(e, id){
36643 // this scrolls the original position back into view
36644 var sm = this.tree.getSelectionModel();
36645 sm.clearSelections();
36646 sm.select(this.dragData.node);
36651 * Ext JS Library 1.1.1
36652 * Copyright(c) 2006-2007, Ext JS, LLC.
36654 * Originally Released Under LGPL - original licence link has changed is not relivant.
36657 * <script type="text/javascript">
36660 * @class Roo.tree.TreeEditor
36661 * @extends Roo.Editor
36662 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36663 * as the editor field.
36665 * @param {Object} config (used to be the tree panel.)
36666 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36668 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36669 * @cfg {Roo.form.TextField|Object} field The field configuration
36673 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36676 if (oldconfig) { // old style..
36677 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36680 tree = config.tree;
36681 config.field = config.field || {};
36682 config.field.xtype = 'TextField';
36683 field = Roo.factory(config.field, Roo.form);
36685 config = config || {};
36690 * @event beforenodeedit
36691 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36692 * false from the handler of this event.
36693 * @param {Editor} this
36694 * @param {Roo.tree.Node} node
36696 "beforenodeedit" : true
36700 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36704 tree.on('beforeclick', this.beforeNodeClick, this);
36705 tree.getTreeEl().on('mousedown', this.hide, this);
36706 this.on('complete', this.updateNode, this);
36707 this.on('beforestartedit', this.fitToTree, this);
36708 this.on('startedit', this.bindScroll, this, {delay:10});
36709 this.on('specialkey', this.onSpecialKey, this);
36712 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36714 * @cfg {String} alignment
36715 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36721 * @cfg {Boolean} hideEl
36722 * True to hide the bound element while the editor is displayed (defaults to false)
36726 * @cfg {String} cls
36727 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36729 cls: "x-small-editor x-tree-editor",
36731 * @cfg {Boolean} shim
36732 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36738 * @cfg {Number} maxWidth
36739 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36740 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36741 * scroll and client offsets into account prior to each edit.
36748 fitToTree : function(ed, el){
36749 var td = this.tree.getTreeEl().dom, nd = el.dom;
36750 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36751 td.scrollLeft = nd.offsetLeft;
36755 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36756 this.setSize(w, '');
36758 return this.fireEvent('beforenodeedit', this, this.editNode);
36763 triggerEdit : function(node){
36764 this.completeEdit();
36765 this.editNode = node;
36766 this.startEdit(node.ui.textNode, node.text);
36770 bindScroll : function(){
36771 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36775 beforeNodeClick : function(node, e){
36776 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36777 this.lastClick = new Date();
36778 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36780 this.triggerEdit(node);
36787 updateNode : function(ed, value){
36788 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36789 this.editNode.setText(value);
36793 onHide : function(){
36794 Roo.tree.TreeEditor.superclass.onHide.call(this);
36796 this.editNode.ui.focus();
36801 onSpecialKey : function(field, e){
36802 var k = e.getKey();
36806 }else if(k == e.ENTER && !e.hasModifier()){
36808 this.completeEdit();
36811 });//<Script type="text/javascript">
36814 * Ext JS Library 1.1.1
36815 * Copyright(c) 2006-2007, Ext JS, LLC.
36817 * Originally Released Under LGPL - original licence link has changed is not relivant.
36820 * <script type="text/javascript">
36824 * Not documented??? - probably should be...
36827 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36828 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36830 renderElements : function(n, a, targetNode, bulkRender){
36831 //consel.log("renderElements?");
36832 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36834 var t = n.getOwnerTree();
36835 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36837 var cols = t.columns;
36838 var bw = t.borderWidth;
36840 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36841 var cb = typeof a.checked == "boolean";
36842 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36843 var colcls = 'x-t-' + tid + '-c0';
36845 '<li class="x-tree-node">',
36848 '<div class="x-tree-node-el ', a.cls,'">',
36850 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36853 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36854 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36855 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36856 (a.icon ? ' x-tree-node-inline-icon' : ''),
36857 (a.iconCls ? ' '+a.iconCls : ''),
36858 '" unselectable="on" />',
36859 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36860 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36862 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36863 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36864 '<span unselectable="on" qtip="' + tx + '">',
36868 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36869 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36871 for(var i = 1, len = cols.length; i < len; i++){
36873 colcls = 'x-t-' + tid + '-c' +i;
36874 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36875 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36876 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36882 '<div class="x-clear"></div></div>',
36883 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36886 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36887 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36888 n.nextSibling.ui.getEl(), buf.join(""));
36890 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36892 var el = this.wrap.firstChild;
36894 this.elNode = el.firstChild;
36895 this.ranchor = el.childNodes[1];
36896 this.ctNode = this.wrap.childNodes[1];
36897 var cs = el.firstChild.childNodes;
36898 this.indentNode = cs[0];
36899 this.ecNode = cs[1];
36900 this.iconNode = cs[2];
36903 this.checkbox = cs[3];
36906 this.anchor = cs[index];
36908 this.textNode = cs[index].firstChild;
36910 //el.on("click", this.onClick, this);
36911 //el.on("dblclick", this.onDblClick, this);
36914 // console.log(this);
36916 initEvents : function(){
36917 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36920 var a = this.ranchor;
36922 var el = Roo.get(a);
36924 if(Roo.isOpera){ // opera render bug ignores the CSS
36925 el.setStyle("text-decoration", "none");
36928 el.on("click", this.onClick, this);
36929 el.on("dblclick", this.onDblClick, this);
36930 el.on("contextmenu", this.onContextMenu, this);
36934 /*onSelectedChange : function(state){
36937 this.addClass("x-tree-selected");
36940 this.removeClass("x-tree-selected");
36943 addClass : function(cls){
36945 Roo.fly(this.elRow).addClass(cls);
36951 removeClass : function(cls){
36953 Roo.fly(this.elRow).removeClass(cls);
36959 });//<Script type="text/javascript">
36963 * Ext JS Library 1.1.1
36964 * Copyright(c) 2006-2007, Ext JS, LLC.
36966 * Originally Released Under LGPL - original licence link has changed is not relivant.
36969 * <script type="text/javascript">
36974 * @class Roo.tree.ColumnTree
36975 * @extends Roo.data.TreePanel
36976 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36977 * @cfg {int} borderWidth compined right/left border allowance
36979 * @param {String/HTMLElement/Element} el The container element
36980 * @param {Object} config
36982 Roo.tree.ColumnTree = function(el, config)
36984 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36988 * Fire this event on a container when it resizes
36989 * @param {int} w Width
36990 * @param {int} h Height
36994 this.on('resize', this.onResize, this);
36997 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37001 borderWidth: Roo.isBorderBox ? 0 : 2,
37004 render : function(){
37005 // add the header.....
37007 Roo.tree.ColumnTree.superclass.render.apply(this);
37009 this.el.addClass('x-column-tree');
37011 this.headers = this.el.createChild(
37012 {cls:'x-tree-headers'},this.innerCt.dom);
37014 var cols = this.columns, c;
37015 var totalWidth = 0;
37017 var len = cols.length;
37018 for(var i = 0; i < len; i++){
37020 totalWidth += c.width;
37021 this.headEls.push(this.headers.createChild({
37022 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37024 cls:'x-tree-hd-text',
37027 style:'width:'+(c.width-this.borderWidth)+'px;'
37030 this.headers.createChild({cls:'x-clear'});
37031 // prevent floats from wrapping when clipped
37032 this.headers.setWidth(totalWidth);
37033 //this.innerCt.setWidth(totalWidth);
37034 this.innerCt.setStyle({ overflow: 'auto' });
37035 this.onResize(this.width, this.height);
37039 onResize : function(w,h)
37044 this.innerCt.setWidth(this.width);
37045 this.innerCt.setHeight(this.height-20);
37048 var cols = this.columns, c;
37049 var totalWidth = 0;
37051 var len = cols.length;
37052 for(var i = 0; i < len; i++){
37054 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37055 // it's the expander..
37056 expEl = this.headEls[i];
37059 totalWidth += c.width;
37063 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37065 this.headers.setWidth(w-20);
37074 * Ext JS Library 1.1.1
37075 * Copyright(c) 2006-2007, Ext JS, LLC.
37077 * Originally Released Under LGPL - original licence link has changed is not relivant.
37080 * <script type="text/javascript">
37084 * @class Roo.menu.Menu
37085 * @extends Roo.util.Observable
37086 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37087 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37089 * Creates a new Menu
37090 * @param {Object} config Configuration options
37092 Roo.menu.Menu = function(config){
37093 Roo.apply(this, config);
37094 this.id = this.id || Roo.id();
37097 * @event beforeshow
37098 * Fires before this menu is displayed
37099 * @param {Roo.menu.Menu} this
37103 * @event beforehide
37104 * Fires before this menu is hidden
37105 * @param {Roo.menu.Menu} this
37110 * Fires after this menu is displayed
37111 * @param {Roo.menu.Menu} this
37116 * Fires after this menu is hidden
37117 * @param {Roo.menu.Menu} this
37122 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37123 * @param {Roo.menu.Menu} this
37124 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37125 * @param {Roo.EventObject} e
37130 * Fires when the mouse is hovering over this menu
37131 * @param {Roo.menu.Menu} this
37132 * @param {Roo.EventObject} e
37133 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37138 * Fires when the mouse exits this menu
37139 * @param {Roo.menu.Menu} this
37140 * @param {Roo.EventObject} e
37141 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37146 * Fires when a menu item contained in this menu is clicked
37147 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37148 * @param {Roo.EventObject} e
37152 if (this.registerMenu) {
37153 Roo.menu.MenuMgr.register(this);
37156 var mis = this.items;
37157 this.items = new Roo.util.MixedCollection();
37159 this.add.apply(this, mis);
37163 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37165 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37169 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37170 * for bottom-right shadow (defaults to "sides")
37174 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37175 * this menu (defaults to "tl-tr?")
37177 subMenuAlign : "tl-tr?",
37179 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37180 * relative to its element of origin (defaults to "tl-bl?")
37182 defaultAlign : "tl-bl?",
37184 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37186 allowOtherMenus : false,
37188 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37190 registerMenu : true,
37195 render : function(){
37199 var el = this.el = new Roo.Layer({
37201 shadow:this.shadow,
37203 parentEl: this.parentEl || document.body,
37207 this.keyNav = new Roo.menu.MenuNav(this);
37210 el.addClass("x-menu-plain");
37213 el.addClass(this.cls);
37215 // generic focus element
37216 this.focusEl = el.createChild({
37217 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37219 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37220 //disabling touch- as it's causing issues ..
37221 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37222 ul.on('click' , this.onClick, this);
37225 ul.on("mouseover", this.onMouseOver, this);
37226 ul.on("mouseout", this.onMouseOut, this);
37227 this.items.each(function(item){
37232 var li = document.createElement("li");
37233 li.className = "x-menu-list-item";
37234 ul.dom.appendChild(li);
37235 item.render(li, this);
37242 autoWidth : function(){
37243 var el = this.el, ul = this.ul;
37247 var w = this.width;
37250 }else if(Roo.isIE){
37251 el.setWidth(this.minWidth);
37252 var t = el.dom.offsetWidth; // force recalc
37253 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37258 delayAutoWidth : function(){
37261 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37263 this.awTask.delay(20);
37268 findTargetItem : function(e){
37269 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37270 if(t && t.menuItemId){
37271 return this.items.get(t.menuItemId);
37276 onClick : function(e){
37277 Roo.log("menu.onClick");
37278 var t = this.findTargetItem(e);
37283 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37284 if(t == this.activeItem && t.shouldDeactivate(e)){
37285 this.activeItem.deactivate();
37286 delete this.activeItem;
37290 this.setActiveItem(t, true);
37298 this.fireEvent("click", this, t, e);
37302 setActiveItem : function(item, autoExpand){
37303 if(item != this.activeItem){
37304 if(this.activeItem){
37305 this.activeItem.deactivate();
37307 this.activeItem = item;
37308 item.activate(autoExpand);
37309 }else if(autoExpand){
37315 tryActivate : function(start, step){
37316 var items = this.items;
37317 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37318 var item = items.get(i);
37319 if(!item.disabled && item.canActivate){
37320 this.setActiveItem(item, false);
37328 onMouseOver : function(e){
37330 if(t = this.findTargetItem(e)){
37331 if(t.canActivate && !t.disabled){
37332 this.setActiveItem(t, true);
37335 this.fireEvent("mouseover", this, e, t);
37339 onMouseOut : function(e){
37341 if(t = this.findTargetItem(e)){
37342 if(t == this.activeItem && t.shouldDeactivate(e)){
37343 this.activeItem.deactivate();
37344 delete this.activeItem;
37347 this.fireEvent("mouseout", this, e, t);
37351 * Read-only. Returns true if the menu is currently displayed, else false.
37354 isVisible : function(){
37355 return this.el && !this.hidden;
37359 * Displays this menu relative to another element
37360 * @param {String/HTMLElement/Roo.Element} element The element to align to
37361 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37362 * the element (defaults to this.defaultAlign)
37363 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37365 show : function(el, pos, parentMenu){
37366 this.parentMenu = parentMenu;
37370 this.fireEvent("beforeshow", this);
37371 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37375 * Displays this menu at a specific xy position
37376 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37377 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37379 showAt : function(xy, parentMenu, /* private: */_e){
37380 this.parentMenu = parentMenu;
37385 this.fireEvent("beforeshow", this);
37386 xy = this.el.adjustForConstraints(xy);
37390 this.hidden = false;
37392 this.fireEvent("show", this);
37395 focus : function(){
37397 this.doFocus.defer(50, this);
37401 doFocus : function(){
37403 this.focusEl.focus();
37408 * Hides this menu and optionally all parent menus
37409 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37411 hide : function(deep){
37412 if(this.el && this.isVisible()){
37413 this.fireEvent("beforehide", this);
37414 if(this.activeItem){
37415 this.activeItem.deactivate();
37416 this.activeItem = null;
37419 this.hidden = true;
37420 this.fireEvent("hide", this);
37422 if(deep === true && this.parentMenu){
37423 this.parentMenu.hide(true);
37428 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37429 * Any of the following are valid:
37431 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37432 * <li>An HTMLElement object which will be converted to a menu item</li>
37433 * <li>A menu item config object that will be created as a new menu item</li>
37434 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37435 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37440 var menu = new Roo.menu.Menu();
37442 // Create a menu item to add by reference
37443 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37445 // Add a bunch of items at once using different methods.
37446 // Only the last item added will be returned.
37447 var item = menu.add(
37448 menuItem, // add existing item by ref
37449 'Dynamic Item', // new TextItem
37450 '-', // new separator
37451 { text: 'Config Item' } // new item by config
37454 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37455 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37458 var a = arguments, l = a.length, item;
37459 for(var i = 0; i < l; i++){
37461 if ((typeof(el) == "object") && el.xtype && el.xns) {
37462 el = Roo.factory(el, Roo.menu);
37465 if(el.render){ // some kind of Item
37466 item = this.addItem(el);
37467 }else if(typeof el == "string"){ // string
37468 if(el == "separator" || el == "-"){
37469 item = this.addSeparator();
37471 item = this.addText(el);
37473 }else if(el.tagName || el.el){ // element
37474 item = this.addElement(el);
37475 }else if(typeof el == "object"){ // must be menu item config?
37476 item = this.addMenuItem(el);
37483 * Returns this menu's underlying {@link Roo.Element} object
37484 * @return {Roo.Element} The element
37486 getEl : function(){
37494 * Adds a separator bar to the menu
37495 * @return {Roo.menu.Item} The menu item that was added
37497 addSeparator : function(){
37498 return this.addItem(new Roo.menu.Separator());
37502 * Adds an {@link Roo.Element} object to the menu
37503 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37504 * @return {Roo.menu.Item} The menu item that was added
37506 addElement : function(el){
37507 return this.addItem(new Roo.menu.BaseItem(el));
37511 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37512 * @param {Roo.menu.Item} item The menu item to add
37513 * @return {Roo.menu.Item} The menu item that was added
37515 addItem : function(item){
37516 this.items.add(item);
37518 var li = document.createElement("li");
37519 li.className = "x-menu-list-item";
37520 this.ul.dom.appendChild(li);
37521 item.render(li, this);
37522 this.delayAutoWidth();
37528 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37529 * @param {Object} config A MenuItem config object
37530 * @return {Roo.menu.Item} The menu item that was added
37532 addMenuItem : function(config){
37533 if(!(config instanceof Roo.menu.Item)){
37534 if(typeof config.checked == "boolean"){ // must be check menu item config?
37535 config = new Roo.menu.CheckItem(config);
37537 config = new Roo.menu.Item(config);
37540 return this.addItem(config);
37544 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37545 * @param {String} text The text to display in the menu item
37546 * @return {Roo.menu.Item} The menu item that was added
37548 addText : function(text){
37549 return this.addItem(new Roo.menu.TextItem({ text : text }));
37553 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37554 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37555 * @param {Roo.menu.Item} item The menu item to add
37556 * @return {Roo.menu.Item} The menu item that was added
37558 insert : function(index, item){
37559 this.items.insert(index, item);
37561 var li = document.createElement("li");
37562 li.className = "x-menu-list-item";
37563 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37564 item.render(li, this);
37565 this.delayAutoWidth();
37571 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37572 * @param {Roo.menu.Item} item The menu item to remove
37574 remove : function(item){
37575 this.items.removeKey(item.id);
37580 * Removes and destroys all items in the menu
37582 removeAll : function(){
37584 while(f = this.items.first()){
37590 // MenuNav is a private utility class used internally by the Menu
37591 Roo.menu.MenuNav = function(menu){
37592 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37593 this.scope = this.menu = menu;
37596 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37597 doRelay : function(e, h){
37598 var k = e.getKey();
37599 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37600 this.menu.tryActivate(0, 1);
37603 return h.call(this.scope || this, e, this.menu);
37606 up : function(e, m){
37607 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37608 m.tryActivate(m.items.length-1, -1);
37612 down : function(e, m){
37613 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37614 m.tryActivate(0, 1);
37618 right : function(e, m){
37620 m.activeItem.expandMenu(true);
37624 left : function(e, m){
37626 if(m.parentMenu && m.parentMenu.activeItem){
37627 m.parentMenu.activeItem.activate();
37631 enter : function(e, m){
37633 e.stopPropagation();
37634 m.activeItem.onClick(e);
37635 m.fireEvent("click", this, m.activeItem);
37641 * Ext JS Library 1.1.1
37642 * Copyright(c) 2006-2007, Ext JS, LLC.
37644 * Originally Released Under LGPL - original licence link has changed is not relivant.
37647 * <script type="text/javascript">
37651 * @class Roo.menu.MenuMgr
37652 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37655 Roo.menu.MenuMgr = function(){
37656 var menus, active, groups = {}, attached = false, lastShow = new Date();
37658 // private - called when first menu is created
37661 active = new Roo.util.MixedCollection();
37662 Roo.get(document).addKeyListener(27, function(){
37663 if(active.length > 0){
37670 function hideAll(){
37671 if(active && active.length > 0){
37672 var c = active.clone();
37673 c.each(function(m){
37680 function onHide(m){
37682 if(active.length < 1){
37683 Roo.get(document).un("mousedown", onMouseDown);
37689 function onShow(m){
37690 var last = active.last();
37691 lastShow = new Date();
37694 Roo.get(document).on("mousedown", onMouseDown);
37698 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37699 m.parentMenu.activeChild = m;
37700 }else if(last && last.isVisible()){
37701 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37706 function onBeforeHide(m){
37708 m.activeChild.hide();
37710 if(m.autoHideTimer){
37711 clearTimeout(m.autoHideTimer);
37712 delete m.autoHideTimer;
37717 function onBeforeShow(m){
37718 var pm = m.parentMenu;
37719 if(!pm && !m.allowOtherMenus){
37721 }else if(pm && pm.activeChild && active != m){
37722 pm.activeChild.hide();
37727 function onMouseDown(e){
37728 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37734 function onBeforeCheck(mi, state){
37736 var g = groups[mi.group];
37737 for(var i = 0, l = g.length; i < l; i++){
37739 g[i].setChecked(false);
37748 * Hides all menus that are currently visible
37750 hideAll : function(){
37755 register : function(menu){
37759 menus[menu.id] = menu;
37760 menu.on("beforehide", onBeforeHide);
37761 menu.on("hide", onHide);
37762 menu.on("beforeshow", onBeforeShow);
37763 menu.on("show", onShow);
37764 var g = menu.group;
37765 if(g && menu.events["checkchange"]){
37769 groups[g].push(menu);
37770 menu.on("checkchange", onCheck);
37775 * Returns a {@link Roo.menu.Menu} object
37776 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37777 * be used to generate and return a new Menu instance.
37779 get : function(menu){
37780 if(typeof menu == "string"){ // menu id
37781 return menus[menu];
37782 }else if(menu.events){ // menu instance
37784 }else if(typeof menu.length == 'number'){ // array of menu items?
37785 return new Roo.menu.Menu({items:menu});
37786 }else{ // otherwise, must be a config
37787 return new Roo.menu.Menu(menu);
37792 unregister : function(menu){
37793 delete menus[menu.id];
37794 menu.un("beforehide", onBeforeHide);
37795 menu.un("hide", onHide);
37796 menu.un("beforeshow", onBeforeShow);
37797 menu.un("show", onShow);
37798 var g = menu.group;
37799 if(g && menu.events["checkchange"]){
37800 groups[g].remove(menu);
37801 menu.un("checkchange", onCheck);
37806 registerCheckable : function(menuItem){
37807 var g = menuItem.group;
37812 groups[g].push(menuItem);
37813 menuItem.on("beforecheckchange", onBeforeCheck);
37818 unregisterCheckable : function(menuItem){
37819 var g = menuItem.group;
37821 groups[g].remove(menuItem);
37822 menuItem.un("beforecheckchange", onBeforeCheck);
37828 * Ext JS Library 1.1.1
37829 * Copyright(c) 2006-2007, Ext JS, LLC.
37831 * Originally Released Under LGPL - original licence link has changed is not relivant.
37834 * <script type="text/javascript">
37839 * @class Roo.menu.BaseItem
37840 * @extends Roo.Component
37841 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37842 * management and base configuration options shared by all menu components.
37844 * Creates a new BaseItem
37845 * @param {Object} config Configuration options
37847 Roo.menu.BaseItem = function(config){
37848 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37853 * Fires when this item is clicked
37854 * @param {Roo.menu.BaseItem} this
37855 * @param {Roo.EventObject} e
37860 * Fires when this item is activated
37861 * @param {Roo.menu.BaseItem} this
37865 * @event deactivate
37866 * Fires when this item is deactivated
37867 * @param {Roo.menu.BaseItem} this
37873 this.on("click", this.handler, this.scope, true);
37877 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37879 * @cfg {Function} handler
37880 * A function that will handle the click event of this menu item (defaults to undefined)
37883 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37885 canActivate : false,
37888 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37893 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37895 activeClass : "x-menu-item-active",
37897 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37899 hideOnClick : true,
37901 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37906 ctype: "Roo.menu.BaseItem",
37909 actionMode : "container",
37912 render : function(container, parentMenu){
37913 this.parentMenu = parentMenu;
37914 Roo.menu.BaseItem.superclass.render.call(this, container);
37915 this.container.menuItemId = this.id;
37919 onRender : function(container, position){
37920 this.el = Roo.get(this.el);
37921 container.dom.appendChild(this.el.dom);
37925 onClick : function(e){
37926 if(!this.disabled && this.fireEvent("click", this, e) !== false
37927 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37928 this.handleClick(e);
37935 activate : function(){
37939 var li = this.container;
37940 li.addClass(this.activeClass);
37941 this.region = li.getRegion().adjust(2, 2, -2, -2);
37942 this.fireEvent("activate", this);
37947 deactivate : function(){
37948 this.container.removeClass(this.activeClass);
37949 this.fireEvent("deactivate", this);
37953 shouldDeactivate : function(e){
37954 return !this.region || !this.region.contains(e.getPoint());
37958 handleClick : function(e){
37959 if(this.hideOnClick){
37960 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37965 expandMenu : function(autoActivate){
37970 hideMenu : function(){
37975 * Ext JS Library 1.1.1
37976 * Copyright(c) 2006-2007, Ext JS, LLC.
37978 * Originally Released Under LGPL - original licence link has changed is not relivant.
37981 * <script type="text/javascript">
37985 * @class Roo.menu.Adapter
37986 * @extends Roo.menu.BaseItem
37987 * 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.
37988 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37990 * Creates a new Adapter
37991 * @param {Object} config Configuration options
37993 Roo.menu.Adapter = function(component, config){
37994 Roo.menu.Adapter.superclass.constructor.call(this, config);
37995 this.component = component;
37997 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
37999 canActivate : true,
38002 onRender : function(container, position){
38003 this.component.render(container);
38004 this.el = this.component.getEl();
38008 activate : function(){
38012 this.component.focus();
38013 this.fireEvent("activate", this);
38018 deactivate : function(){
38019 this.fireEvent("deactivate", this);
38023 disable : function(){
38024 this.component.disable();
38025 Roo.menu.Adapter.superclass.disable.call(this);
38029 enable : function(){
38030 this.component.enable();
38031 Roo.menu.Adapter.superclass.enable.call(this);
38035 * Ext JS Library 1.1.1
38036 * Copyright(c) 2006-2007, Ext JS, LLC.
38038 * Originally Released Under LGPL - original licence link has changed is not relivant.
38041 * <script type="text/javascript">
38045 * @class Roo.menu.TextItem
38046 * @extends Roo.menu.BaseItem
38047 * Adds a static text string to a menu, usually used as either a heading or group separator.
38048 * Note: old style constructor with text is still supported.
38051 * Creates a new TextItem
38052 * @param {Object} cfg Configuration
38054 Roo.menu.TextItem = function(cfg){
38055 if (typeof(cfg) == 'string') {
38058 Roo.apply(this,cfg);
38061 Roo.menu.TextItem.superclass.constructor.call(this);
38064 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38066 * @cfg {Boolean} text Text to show on item.
38071 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38073 hideOnClick : false,
38075 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38077 itemCls : "x-menu-text",
38080 onRender : function(){
38081 var s = document.createElement("span");
38082 s.className = this.itemCls;
38083 s.innerHTML = this.text;
38085 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38089 * Ext JS Library 1.1.1
38090 * Copyright(c) 2006-2007, Ext JS, LLC.
38092 * Originally Released Under LGPL - original licence link has changed is not relivant.
38095 * <script type="text/javascript">
38099 * @class Roo.menu.Separator
38100 * @extends Roo.menu.BaseItem
38101 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38102 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38104 * @param {Object} config Configuration options
38106 Roo.menu.Separator = function(config){
38107 Roo.menu.Separator.superclass.constructor.call(this, config);
38110 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38112 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38114 itemCls : "x-menu-sep",
38116 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38118 hideOnClick : false,
38121 onRender : function(li){
38122 var s = document.createElement("span");
38123 s.className = this.itemCls;
38124 s.innerHTML = " ";
38126 li.addClass("x-menu-sep-li");
38127 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38131 * Ext JS Library 1.1.1
38132 * Copyright(c) 2006-2007, Ext JS, LLC.
38134 * Originally Released Under LGPL - original licence link has changed is not relivant.
38137 * <script type="text/javascript">
38140 * @class Roo.menu.Item
38141 * @extends Roo.menu.BaseItem
38142 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38143 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38144 * activation and click handling.
38146 * Creates a new Item
38147 * @param {Object} config Configuration options
38149 Roo.menu.Item = function(config){
38150 Roo.menu.Item.superclass.constructor.call(this, config);
38152 this.menu = Roo.menu.MenuMgr.get(this.menu);
38155 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38158 * @cfg {String} text
38159 * The text to show on the menu item.
38163 * @cfg {String} HTML to render in menu
38164 * The text to show on the menu item (HTML version).
38168 * @cfg {String} icon
38169 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38173 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38175 itemCls : "x-menu-item",
38177 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38179 canActivate : true,
38181 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38184 // doc'd in BaseItem
38188 ctype: "Roo.menu.Item",
38191 onRender : function(container, position){
38192 var el = document.createElement("a");
38193 el.hideFocus = true;
38194 el.unselectable = "on";
38195 el.href = this.href || "#";
38196 if(this.hrefTarget){
38197 el.target = this.hrefTarget;
38199 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38201 var html = this.html.length ? this.html : String.format('{0}',this.text);
38203 el.innerHTML = String.format(
38204 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38205 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38207 Roo.menu.Item.superclass.onRender.call(this, container, position);
38211 * Sets the text to display in this menu item
38212 * @param {String} text The text to display
38213 * @param {Boolean} isHTML true to indicate text is pure html.
38215 setText : function(text, isHTML){
38223 var html = this.html.length ? this.html : String.format('{0}',this.text);
38225 this.el.update(String.format(
38226 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38227 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38228 this.parentMenu.autoWidth();
38233 handleClick : function(e){
38234 if(!this.href){ // if no link defined, stop the event automatically
38237 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38241 activate : function(autoExpand){
38242 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38252 shouldDeactivate : function(e){
38253 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38254 if(this.menu && this.menu.isVisible()){
38255 return !this.menu.getEl().getRegion().contains(e.getPoint());
38263 deactivate : function(){
38264 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38269 expandMenu : function(autoActivate){
38270 if(!this.disabled && this.menu){
38271 clearTimeout(this.hideTimer);
38272 delete this.hideTimer;
38273 if(!this.menu.isVisible() && !this.showTimer){
38274 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38275 }else if (this.menu.isVisible() && autoActivate){
38276 this.menu.tryActivate(0, 1);
38282 deferExpand : function(autoActivate){
38283 delete this.showTimer;
38284 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38286 this.menu.tryActivate(0, 1);
38291 hideMenu : function(){
38292 clearTimeout(this.showTimer);
38293 delete this.showTimer;
38294 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38295 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38300 deferHide : function(){
38301 delete this.hideTimer;
38306 * Ext JS Library 1.1.1
38307 * Copyright(c) 2006-2007, Ext JS, LLC.
38309 * Originally Released Under LGPL - original licence link has changed is not relivant.
38312 * <script type="text/javascript">
38316 * @class Roo.menu.CheckItem
38317 * @extends Roo.menu.Item
38318 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38320 * Creates a new CheckItem
38321 * @param {Object} config Configuration options
38323 Roo.menu.CheckItem = function(config){
38324 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38327 * @event beforecheckchange
38328 * Fires before the checked value is set, providing an opportunity to cancel if needed
38329 * @param {Roo.menu.CheckItem} this
38330 * @param {Boolean} checked The new checked value that will be set
38332 "beforecheckchange" : true,
38334 * @event checkchange
38335 * Fires after the checked value has been set
38336 * @param {Roo.menu.CheckItem} this
38337 * @param {Boolean} checked The checked value that was set
38339 "checkchange" : true
38341 if(this.checkHandler){
38342 this.on('checkchange', this.checkHandler, this.scope);
38345 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38347 * @cfg {String} group
38348 * All check items with the same group name will automatically be grouped into a single-select
38349 * radio button group (defaults to '')
38352 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38354 itemCls : "x-menu-item x-menu-check-item",
38356 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38358 groupClass : "x-menu-group-item",
38361 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38362 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38363 * initialized with checked = true will be rendered as checked.
38368 ctype: "Roo.menu.CheckItem",
38371 onRender : function(c){
38372 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38374 this.el.addClass(this.groupClass);
38376 Roo.menu.MenuMgr.registerCheckable(this);
38378 this.checked = false;
38379 this.setChecked(true, true);
38384 destroy : function(){
38386 Roo.menu.MenuMgr.unregisterCheckable(this);
38388 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38392 * Set the checked state of this item
38393 * @param {Boolean} checked The new checked value
38394 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38396 setChecked : function(state, suppressEvent){
38397 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38398 if(this.container){
38399 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38401 this.checked = state;
38402 if(suppressEvent !== true){
38403 this.fireEvent("checkchange", this, state);
38409 handleClick : function(e){
38410 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38411 this.setChecked(!this.checked);
38413 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38417 * Ext JS Library 1.1.1
38418 * Copyright(c) 2006-2007, Ext JS, LLC.
38420 * Originally Released Under LGPL - original licence link has changed is not relivant.
38423 * <script type="text/javascript">
38427 * @class Roo.menu.DateItem
38428 * @extends Roo.menu.Adapter
38429 * A menu item that wraps the {@link Roo.DatPicker} component.
38431 * Creates a new DateItem
38432 * @param {Object} config Configuration options
38434 Roo.menu.DateItem = function(config){
38435 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38436 /** The Roo.DatePicker object @type Roo.DatePicker */
38437 this.picker = this.component;
38438 this.addEvents({select: true});
38440 this.picker.on("render", function(picker){
38441 picker.getEl().swallowEvent("click");
38442 picker.container.addClass("x-menu-date-item");
38445 this.picker.on("select", this.onSelect, this);
38448 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38450 onSelect : function(picker, date){
38451 this.fireEvent("select", this, date, picker);
38452 Roo.menu.DateItem.superclass.handleClick.call(this);
38456 * Ext JS Library 1.1.1
38457 * Copyright(c) 2006-2007, Ext JS, LLC.
38459 * Originally Released Under LGPL - original licence link has changed is not relivant.
38462 * <script type="text/javascript">
38466 * @class Roo.menu.ColorItem
38467 * @extends Roo.menu.Adapter
38468 * A menu item that wraps the {@link Roo.ColorPalette} component.
38470 * Creates a new ColorItem
38471 * @param {Object} config Configuration options
38473 Roo.menu.ColorItem = function(config){
38474 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38475 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38476 this.palette = this.component;
38477 this.relayEvents(this.palette, ["select"]);
38478 if(this.selectHandler){
38479 this.on('select', this.selectHandler, this.scope);
38482 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38484 * Ext JS Library 1.1.1
38485 * Copyright(c) 2006-2007, Ext JS, LLC.
38487 * Originally Released Under LGPL - original licence link has changed is not relivant.
38490 * <script type="text/javascript">
38495 * @class Roo.menu.DateMenu
38496 * @extends Roo.menu.Menu
38497 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38499 * Creates a new DateMenu
38500 * @param {Object} config Configuration options
38502 Roo.menu.DateMenu = function(config){
38503 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38505 var di = new Roo.menu.DateItem(config);
38508 * The {@link Roo.DatePicker} instance for this DateMenu
38511 this.picker = di.picker;
38514 * @param {DatePicker} picker
38515 * @param {Date} date
38517 this.relayEvents(di, ["select"]);
38518 this.on('beforeshow', function(){
38520 this.picker.hideMonthPicker(false);
38524 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38528 * Ext JS Library 1.1.1
38529 * Copyright(c) 2006-2007, Ext JS, LLC.
38531 * Originally Released Under LGPL - original licence link has changed is not relivant.
38534 * <script type="text/javascript">
38539 * @class Roo.menu.ColorMenu
38540 * @extends Roo.menu.Menu
38541 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38543 * Creates a new ColorMenu
38544 * @param {Object} config Configuration options
38546 Roo.menu.ColorMenu = function(config){
38547 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38549 var ci = new Roo.menu.ColorItem(config);
38552 * The {@link Roo.ColorPalette} instance for this ColorMenu
38553 * @type ColorPalette
38555 this.palette = ci.palette;
38558 * @param {ColorPalette} palette
38559 * @param {String} color
38561 this.relayEvents(ci, ["select"]);
38563 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38565 * Ext JS Library 1.1.1
38566 * Copyright(c) 2006-2007, Ext JS, LLC.
38568 * Originally Released Under LGPL - original licence link has changed is not relivant.
38571 * <script type="text/javascript">
38575 * @class Roo.form.Field
38576 * @extends Roo.BoxComponent
38577 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38579 * Creates a new Field
38580 * @param {Object} config Configuration options
38582 Roo.form.Field = function(config){
38583 Roo.form.Field.superclass.constructor.call(this, config);
38586 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38588 * @cfg {String} fieldLabel Label to use when rendering a form.
38591 * @cfg {String} qtip Mouse over tip
38595 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38597 invalidClass : "x-form-invalid",
38599 * @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")
38601 invalidText : "The value in this field is invalid",
38603 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38605 focusClass : "x-form-focus",
38607 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38608 automatic validation (defaults to "keyup").
38610 validationEvent : "keyup",
38612 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38614 validateOnBlur : true,
38616 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38618 validationDelay : 250,
38620 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38621 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38623 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38625 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38627 fieldClass : "x-form-field",
38629 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38632 ----------- ----------------------------------------------------------------------
38633 qtip Display a quick tip when the user hovers over the field
38634 title Display a default browser title attribute popup
38635 under Add a block div beneath the field containing the error text
38636 side Add an error icon to the right of the field with a popup on hover
38637 [element id] Add the error text directly to the innerHTML of the specified element
38640 msgTarget : 'qtip',
38642 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38647 * @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.
38652 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38657 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38659 inputType : undefined,
38662 * @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).
38664 tabIndex : undefined,
38667 isFormField : true,
38672 * @property {Roo.Element} fieldEl
38673 * Element Containing the rendered Field (with label etc.)
38676 * @cfg {Mixed} value A value to initialize this field with.
38681 * @cfg {String} name The field's HTML name attribute.
38684 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38687 loadedValue : false,
38691 initComponent : function(){
38692 Roo.form.Field.superclass.initComponent.call(this);
38696 * Fires when this field receives input focus.
38697 * @param {Roo.form.Field} this
38702 * Fires when this field loses input focus.
38703 * @param {Roo.form.Field} this
38707 * @event specialkey
38708 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38709 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38710 * @param {Roo.form.Field} this
38711 * @param {Roo.EventObject} e The event object
38716 * Fires just before the field blurs if the field value has changed.
38717 * @param {Roo.form.Field} this
38718 * @param {Mixed} newValue The new value
38719 * @param {Mixed} oldValue The original value
38724 * Fires after the field has been marked as invalid.
38725 * @param {Roo.form.Field} this
38726 * @param {String} msg The validation message
38731 * Fires after the field has been validated with no errors.
38732 * @param {Roo.form.Field} this
38737 * Fires after the key up
38738 * @param {Roo.form.Field} this
38739 * @param {Roo.EventObject} e The event Object
38746 * Returns the name attribute of the field if available
38747 * @return {String} name The field name
38749 getName: function(){
38750 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38754 onRender : function(ct, position){
38755 Roo.form.Field.superclass.onRender.call(this, ct, position);
38757 var cfg = this.getAutoCreate();
38759 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38761 if (!cfg.name.length) {
38764 if(this.inputType){
38765 cfg.type = this.inputType;
38767 this.el = ct.createChild(cfg, position);
38769 var type = this.el.dom.type;
38771 if(type == 'password'){
38774 this.el.addClass('x-form-'+type);
38777 this.el.dom.readOnly = true;
38779 if(this.tabIndex !== undefined){
38780 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38783 this.el.addClass([this.fieldClass, this.cls]);
38788 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38789 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38790 * @return {Roo.form.Field} this
38792 applyTo : function(target){
38793 this.allowDomMove = false;
38794 this.el = Roo.get(target);
38795 this.render(this.el.dom.parentNode);
38800 initValue : function(){
38801 if(this.value !== undefined){
38802 this.setValue(this.value);
38803 }else if(this.el.dom.value.length > 0){
38804 this.setValue(this.el.dom.value);
38809 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38810 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38812 isDirty : function() {
38813 if(this.disabled) {
38816 return String(this.getValue()) !== String(this.originalValue);
38820 * stores the current value in loadedValue
38822 resetHasChanged : function()
38824 this.loadedValue = String(this.getValue());
38827 * checks the current value against the 'loaded' value.
38828 * Note - will return false if 'resetHasChanged' has not been called first.
38830 hasChanged : function()
38832 if(this.disabled || this.readOnly) {
38835 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38841 afterRender : function(){
38842 Roo.form.Field.superclass.afterRender.call(this);
38847 fireKey : function(e){
38848 //Roo.log('field ' + e.getKey());
38849 if(e.isNavKeyPress()){
38850 this.fireEvent("specialkey", this, e);
38855 * Resets the current field value to the originally loaded value and clears any validation messages
38857 reset : function(){
38858 this.setValue(this.resetValue);
38859 this.clearInvalid();
38863 initEvents : function(){
38864 // safari killled keypress - so keydown is now used..
38865 this.el.on("keydown" , this.fireKey, this);
38866 this.el.on("focus", this.onFocus, this);
38867 this.el.on("blur", this.onBlur, this);
38868 this.el.relayEvent('keyup', this);
38870 // reference to original value for reset
38871 this.originalValue = this.getValue();
38872 this.resetValue = this.getValue();
38876 onFocus : function(){
38877 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38878 this.el.addClass(this.focusClass);
38880 if(!this.hasFocus){
38881 this.hasFocus = true;
38882 this.startValue = this.getValue();
38883 this.fireEvent("focus", this);
38887 beforeBlur : Roo.emptyFn,
38890 onBlur : function(){
38892 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38893 this.el.removeClass(this.focusClass);
38895 this.hasFocus = false;
38896 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38899 var v = this.getValue();
38900 if(String(v) !== String(this.startValue)){
38901 this.fireEvent('change', this, v, this.startValue);
38903 this.fireEvent("blur", this);
38907 * Returns whether or not the field value is currently valid
38908 * @param {Boolean} preventMark True to disable marking the field invalid
38909 * @return {Boolean} True if the value is valid, else false
38911 isValid : function(preventMark){
38915 var restore = this.preventMark;
38916 this.preventMark = preventMark === true;
38917 var v = this.validateValue(this.processValue(this.getRawValue()));
38918 this.preventMark = restore;
38923 * Validates the field value
38924 * @return {Boolean} True if the value is valid, else false
38926 validate : function(){
38927 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38928 this.clearInvalid();
38934 processValue : function(value){
38939 // Subclasses should provide the validation implementation by overriding this
38940 validateValue : function(value){
38945 * Mark this field as invalid
38946 * @param {String} msg The validation message
38948 markInvalid : function(msg){
38949 if(!this.rendered || this.preventMark){ // not rendered
38953 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38955 obj.el.addClass(this.invalidClass);
38956 msg = msg || this.invalidText;
38957 switch(this.msgTarget){
38959 obj.el.dom.qtip = msg;
38960 obj.el.dom.qclass = 'x-form-invalid-tip';
38961 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38962 Roo.QuickTips.enable();
38966 this.el.dom.title = msg;
38970 var elp = this.el.findParent('.x-form-element', 5, true);
38971 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38972 this.errorEl.setWidth(elp.getWidth(true)-20);
38974 this.errorEl.update(msg);
38975 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38978 if(!this.errorIcon){
38979 var elp = this.el.findParent('.x-form-element', 5, true);
38980 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38982 this.alignErrorIcon();
38983 this.errorIcon.dom.qtip = msg;
38984 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38985 this.errorIcon.show();
38986 this.on('resize', this.alignErrorIcon, this);
38989 var t = Roo.getDom(this.msgTarget);
38991 t.style.display = this.msgDisplay;
38994 this.fireEvent('invalid', this, msg);
38998 alignErrorIcon : function(){
38999 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39003 * Clear any invalid styles/messages for this field
39005 clearInvalid : function(){
39006 if(!this.rendered || this.preventMark){ // not rendered
39009 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39011 obj.el.removeClass(this.invalidClass);
39012 switch(this.msgTarget){
39014 obj.el.dom.qtip = '';
39017 this.el.dom.title = '';
39021 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39025 if(this.errorIcon){
39026 this.errorIcon.dom.qtip = '';
39027 this.errorIcon.hide();
39028 this.un('resize', this.alignErrorIcon, this);
39032 var t = Roo.getDom(this.msgTarget);
39034 t.style.display = 'none';
39037 this.fireEvent('valid', this);
39041 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39042 * @return {Mixed} value The field value
39044 getRawValue : function(){
39045 var v = this.el.getValue();
39051 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39052 * @return {Mixed} value The field value
39054 getValue : function(){
39055 var v = this.el.getValue();
39061 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39062 * @param {Mixed} value The value to set
39064 setRawValue : function(v){
39065 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39069 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39070 * @param {Mixed} value The value to set
39072 setValue : function(v){
39075 this.el.dom.value = (v === null || v === undefined ? '' : v);
39080 adjustSize : function(w, h){
39081 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39082 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39086 adjustWidth : function(tag, w){
39087 tag = tag.toLowerCase();
39088 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39089 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39090 if(tag == 'input'){
39093 if(tag == 'textarea'){
39096 }else if(Roo.isOpera){
39097 if(tag == 'input'){
39100 if(tag == 'textarea'){
39110 // anything other than normal should be considered experimental
39111 Roo.form.Field.msgFx = {
39113 show: function(msgEl, f){
39114 msgEl.setDisplayed('block');
39117 hide : function(msgEl, f){
39118 msgEl.setDisplayed(false).update('');
39123 show: function(msgEl, f){
39124 msgEl.slideIn('t', {stopFx:true});
39127 hide : function(msgEl, f){
39128 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39133 show: function(msgEl, f){
39134 msgEl.fixDisplay();
39135 msgEl.alignTo(f.el, 'tl-tr');
39136 msgEl.slideIn('l', {stopFx:true});
39139 hide : function(msgEl, f){
39140 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39145 * Ext JS Library 1.1.1
39146 * Copyright(c) 2006-2007, Ext JS, LLC.
39148 * Originally Released Under LGPL - original licence link has changed is not relivant.
39151 * <script type="text/javascript">
39156 * @class Roo.form.TextField
39157 * @extends Roo.form.Field
39158 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39159 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39161 * Creates a new TextField
39162 * @param {Object} config Configuration options
39164 Roo.form.TextField = function(config){
39165 Roo.form.TextField.superclass.constructor.call(this, config);
39169 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39170 * according to the default logic, but this event provides a hook for the developer to apply additional
39171 * logic at runtime to resize the field if needed.
39172 * @param {Roo.form.Field} this This text field
39173 * @param {Number} width The new field width
39179 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39181 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39185 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39189 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39193 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39197 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39201 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39203 disableKeyFilter : false,
39205 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39209 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39213 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39215 maxLength : Number.MAX_VALUE,
39217 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39219 minLengthText : "The minimum length for this field is {0}",
39221 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39223 maxLengthText : "The maximum length for this field is {0}",
39225 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39227 selectOnFocus : false,
39229 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39231 blankText : "This field is required",
39233 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39234 * If available, this function will be called only after the basic validators all return true, and will be passed the
39235 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39239 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39240 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39241 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39245 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39249 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39255 initEvents : function()
39257 if (this.emptyText) {
39258 this.el.attr('placeholder', this.emptyText);
39261 Roo.form.TextField.superclass.initEvents.call(this);
39262 if(this.validationEvent == 'keyup'){
39263 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39264 this.el.on('keyup', this.filterValidation, this);
39266 else if(this.validationEvent !== false){
39267 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39270 if(this.selectOnFocus){
39271 this.on("focus", this.preFocus, this);
39274 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39275 this.el.on("keypress", this.filterKeys, this);
39278 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39279 this.el.on("click", this.autoSize, this);
39281 if(this.el.is('input[type=password]') && Roo.isSafari){
39282 this.el.on('keydown', this.SafariOnKeyDown, this);
39286 processValue : function(value){
39287 if(this.stripCharsRe){
39288 var newValue = value.replace(this.stripCharsRe, '');
39289 if(newValue !== value){
39290 this.setRawValue(newValue);
39297 filterValidation : function(e){
39298 if(!e.isNavKeyPress()){
39299 this.validationTask.delay(this.validationDelay);
39304 onKeyUp : function(e){
39305 if(!e.isNavKeyPress()){
39311 * Resets the current field value to the originally-loaded value and clears any validation messages.
39314 reset : function(){
39315 Roo.form.TextField.superclass.reset.call(this);
39321 preFocus : function(){
39323 if(this.selectOnFocus){
39324 this.el.dom.select();
39330 filterKeys : function(e){
39331 var k = e.getKey();
39332 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39335 var c = e.getCharCode(), cc = String.fromCharCode(c);
39336 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39339 if(!this.maskRe.test(cc)){
39344 setValue : function(v){
39346 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39352 * Validates a value according to the field's validation rules and marks the field as invalid
39353 * if the validation fails
39354 * @param {Mixed} value The value to validate
39355 * @return {Boolean} True if the value is valid, else false
39357 validateValue : function(value){
39358 if(value.length < 1) { // if it's blank
39359 if(this.allowBlank){
39360 this.clearInvalid();
39363 this.markInvalid(this.blankText);
39367 if(value.length < this.minLength){
39368 this.markInvalid(String.format(this.minLengthText, this.minLength));
39371 if(value.length > this.maxLength){
39372 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39376 var vt = Roo.form.VTypes;
39377 if(!vt[this.vtype](value, this)){
39378 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39382 if(typeof this.validator == "function"){
39383 var msg = this.validator(value);
39385 this.markInvalid(msg);
39389 if(this.regex && !this.regex.test(value)){
39390 this.markInvalid(this.regexText);
39397 * Selects text in this field
39398 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39399 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39401 selectText : function(start, end){
39402 var v = this.getRawValue();
39404 start = start === undefined ? 0 : start;
39405 end = end === undefined ? v.length : end;
39406 var d = this.el.dom;
39407 if(d.setSelectionRange){
39408 d.setSelectionRange(start, end);
39409 }else if(d.createTextRange){
39410 var range = d.createTextRange();
39411 range.moveStart("character", start);
39412 range.moveEnd("character", v.length-end);
39419 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39420 * This only takes effect if grow = true, and fires the autosize event.
39422 autoSize : function(){
39423 if(!this.grow || !this.rendered){
39427 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39430 var v = el.dom.value;
39431 var d = document.createElement('div');
39432 d.appendChild(document.createTextNode(v));
39436 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39437 this.el.setWidth(w);
39438 this.fireEvent("autosize", this, w);
39442 SafariOnKeyDown : function(event)
39444 // this is a workaround for a password hang bug on chrome/ webkit.
39446 var isSelectAll = false;
39448 if(this.el.dom.selectionEnd > 0){
39449 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39451 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39452 event.preventDefault();
39457 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39459 event.preventDefault();
39460 // this is very hacky as keydown always get's upper case.
39462 var cc = String.fromCharCode(event.getCharCode());
39465 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39473 * Ext JS Library 1.1.1
39474 * Copyright(c) 2006-2007, Ext JS, LLC.
39476 * Originally Released Under LGPL - original licence link has changed is not relivant.
39479 * <script type="text/javascript">
39483 * @class Roo.form.Hidden
39484 * @extends Roo.form.TextField
39485 * Simple Hidden element used on forms
39487 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39490 * Creates a new Hidden form element.
39491 * @param {Object} config Configuration options
39496 // easy hidden field...
39497 Roo.form.Hidden = function(config){
39498 Roo.form.Hidden.superclass.constructor.call(this, config);
39501 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39503 inputType: 'hidden',
39506 labelSeparator: '',
39508 itemCls : 'x-form-item-display-none'
39516 * Ext JS Library 1.1.1
39517 * Copyright(c) 2006-2007, Ext JS, LLC.
39519 * Originally Released Under LGPL - original licence link has changed is not relivant.
39522 * <script type="text/javascript">
39526 * @class Roo.form.TriggerField
39527 * @extends Roo.form.TextField
39528 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39529 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39530 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39531 * for which you can provide a custom implementation. For example:
39533 var trigger = new Roo.form.TriggerField();
39534 trigger.onTriggerClick = myTriggerFn;
39535 trigger.applyTo('my-field');
39538 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39539 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39540 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39541 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39543 * Create a new TriggerField.
39544 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39545 * to the base TextField)
39547 Roo.form.TriggerField = function(config){
39548 this.mimicing = false;
39549 Roo.form.TriggerField.superclass.constructor.call(this, config);
39552 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39554 * @cfg {String} triggerClass A CSS class to apply to the trigger
39557 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39558 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39560 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39562 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39566 /** @cfg {Boolean} grow @hide */
39567 /** @cfg {Number} growMin @hide */
39568 /** @cfg {Number} growMax @hide */
39574 autoSize: Roo.emptyFn,
39578 deferHeight : true,
39581 actionMode : 'wrap',
39583 onResize : function(w, h){
39584 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39585 if(typeof w == 'number'){
39586 var x = w - this.trigger.getWidth();
39587 this.el.setWidth(this.adjustWidth('input', x));
39588 this.trigger.setStyle('left', x+'px');
39593 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39596 getResizeEl : function(){
39601 getPositionEl : function(){
39606 alignErrorIcon : function(){
39607 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39611 onRender : function(ct, position){
39612 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39613 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39614 this.trigger = this.wrap.createChild(this.triggerConfig ||
39615 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39616 if(this.hideTrigger){
39617 this.trigger.setDisplayed(false);
39619 this.initTrigger();
39621 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39626 initTrigger : function(){
39627 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39628 this.trigger.addClassOnOver('x-form-trigger-over');
39629 this.trigger.addClassOnClick('x-form-trigger-click');
39633 onDestroy : function(){
39635 this.trigger.removeAllListeners();
39636 this.trigger.remove();
39639 this.wrap.remove();
39641 Roo.form.TriggerField.superclass.onDestroy.call(this);
39645 onFocus : function(){
39646 Roo.form.TriggerField.superclass.onFocus.call(this);
39647 if(!this.mimicing){
39648 this.wrap.addClass('x-trigger-wrap-focus');
39649 this.mimicing = true;
39650 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39651 if(this.monitorTab){
39652 this.el.on("keydown", this.checkTab, this);
39658 checkTab : function(e){
39659 if(e.getKey() == e.TAB){
39660 this.triggerBlur();
39665 onBlur : function(){
39670 mimicBlur : function(e, t){
39671 if(!this.wrap.contains(t) && this.validateBlur()){
39672 this.triggerBlur();
39677 triggerBlur : function(){
39678 this.mimicing = false;
39679 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39680 if(this.monitorTab){
39681 this.el.un("keydown", this.checkTab, this);
39683 this.wrap.removeClass('x-trigger-wrap-focus');
39684 Roo.form.TriggerField.superclass.onBlur.call(this);
39688 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39689 validateBlur : function(e, t){
39694 onDisable : function(){
39695 Roo.form.TriggerField.superclass.onDisable.call(this);
39697 this.wrap.addClass('x-item-disabled');
39702 onEnable : function(){
39703 Roo.form.TriggerField.superclass.onEnable.call(this);
39705 this.wrap.removeClass('x-item-disabled');
39710 onShow : function(){
39711 var ae = this.getActionEl();
39714 ae.dom.style.display = '';
39715 ae.dom.style.visibility = 'visible';
39721 onHide : function(){
39722 var ae = this.getActionEl();
39723 ae.dom.style.display = 'none';
39727 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39728 * by an implementing function.
39730 * @param {EventObject} e
39732 onTriggerClick : Roo.emptyFn
39735 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39736 // to be extended by an implementing class. For an example of implementing this class, see the custom
39737 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39738 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39739 initComponent : function(){
39740 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39742 this.triggerConfig = {
39743 tag:'span', cls:'x-form-twin-triggers', cn:[
39744 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39745 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39749 getTrigger : function(index){
39750 return this.triggers[index];
39753 initTrigger : function(){
39754 var ts = this.trigger.select('.x-form-trigger', true);
39755 this.wrap.setStyle('overflow', 'hidden');
39756 var triggerField = this;
39757 ts.each(function(t, all, index){
39758 t.hide = function(){
39759 var w = triggerField.wrap.getWidth();
39760 this.dom.style.display = 'none';
39761 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39763 t.show = function(){
39764 var w = triggerField.wrap.getWidth();
39765 this.dom.style.display = '';
39766 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39768 var triggerIndex = 'Trigger'+(index+1);
39770 if(this['hide'+triggerIndex]){
39771 t.dom.style.display = 'none';
39773 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39774 t.addClassOnOver('x-form-trigger-over');
39775 t.addClassOnClick('x-form-trigger-click');
39777 this.triggers = ts.elements;
39780 onTrigger1Click : Roo.emptyFn,
39781 onTrigger2Click : Roo.emptyFn
39784 * Ext JS Library 1.1.1
39785 * Copyright(c) 2006-2007, Ext JS, LLC.
39787 * Originally Released Under LGPL - original licence link has changed is not relivant.
39790 * <script type="text/javascript">
39794 * @class Roo.form.TextArea
39795 * @extends Roo.form.TextField
39796 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39797 * support for auto-sizing.
39799 * Creates a new TextArea
39800 * @param {Object} config Configuration options
39802 Roo.form.TextArea = function(config){
39803 Roo.form.TextArea.superclass.constructor.call(this, config);
39804 // these are provided exchanges for backwards compat
39805 // minHeight/maxHeight were replaced by growMin/growMax to be
39806 // compatible with TextField growing config values
39807 if(this.minHeight !== undefined){
39808 this.growMin = this.minHeight;
39810 if(this.maxHeight !== undefined){
39811 this.growMax = this.maxHeight;
39815 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39817 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39821 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39825 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39826 * in the field (equivalent to setting overflow: hidden, defaults to false)
39828 preventScrollbars: false,
39830 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39831 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39835 onRender : function(ct, position){
39837 this.defaultAutoCreate = {
39839 style:"width:300px;height:60px;",
39840 autocomplete: "new-password"
39843 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39845 this.textSizeEl = Roo.DomHelper.append(document.body, {
39846 tag: "pre", cls: "x-form-grow-sizer"
39848 if(this.preventScrollbars){
39849 this.el.setStyle("overflow", "hidden");
39851 this.el.setHeight(this.growMin);
39855 onDestroy : function(){
39856 if(this.textSizeEl){
39857 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39859 Roo.form.TextArea.superclass.onDestroy.call(this);
39863 onKeyUp : function(e){
39864 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39870 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39871 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39873 autoSize : function(){
39874 if(!this.grow || !this.textSizeEl){
39878 var v = el.dom.value;
39879 var ts = this.textSizeEl;
39882 ts.appendChild(document.createTextNode(v));
39885 Roo.fly(ts).setWidth(this.el.getWidth());
39887 v = "  ";
39890 v = v.replace(/\n/g, '<p> </p>');
39892 v += " \n ";
39895 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39896 if(h != this.lastHeight){
39897 this.lastHeight = h;
39898 this.el.setHeight(h);
39899 this.fireEvent("autosize", this, h);
39904 * Ext JS Library 1.1.1
39905 * Copyright(c) 2006-2007, Ext JS, LLC.
39907 * Originally Released Under LGPL - original licence link has changed is not relivant.
39910 * <script type="text/javascript">
39915 * @class Roo.form.NumberField
39916 * @extends Roo.form.TextField
39917 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39919 * Creates a new NumberField
39920 * @param {Object} config Configuration options
39922 Roo.form.NumberField = function(config){
39923 Roo.form.NumberField.superclass.constructor.call(this, config);
39926 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39928 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39930 fieldClass: "x-form-field x-form-num-field",
39932 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39934 allowDecimals : true,
39936 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39938 decimalSeparator : ".",
39940 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39942 decimalPrecision : 2,
39944 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39946 allowNegative : true,
39948 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39950 minValue : Number.NEGATIVE_INFINITY,
39952 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39954 maxValue : Number.MAX_VALUE,
39956 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39958 minText : "The minimum value for this field is {0}",
39960 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39962 maxText : "The maximum value for this field is {0}",
39964 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39965 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39967 nanText : "{0} is not a valid number",
39970 initEvents : function(){
39971 Roo.form.NumberField.superclass.initEvents.call(this);
39972 var allowed = "0123456789";
39973 if(this.allowDecimals){
39974 allowed += this.decimalSeparator;
39976 if(this.allowNegative){
39979 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39980 var keyPress = function(e){
39981 var k = e.getKey();
39982 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39985 var c = e.getCharCode();
39986 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39990 this.el.on("keypress", keyPress, this);
39994 validateValue : function(value){
39995 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
39998 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40001 var num = this.parseValue(value);
40003 this.markInvalid(String.format(this.nanText, value));
40006 if(num < this.minValue){
40007 this.markInvalid(String.format(this.minText, this.minValue));
40010 if(num > this.maxValue){
40011 this.markInvalid(String.format(this.maxText, this.maxValue));
40017 getValue : function(){
40018 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40022 parseValue : function(value){
40023 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40024 return isNaN(value) ? '' : value;
40028 fixPrecision : function(value){
40029 var nan = isNaN(value);
40030 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40031 return nan ? '' : value;
40033 return parseFloat(value).toFixed(this.decimalPrecision);
40036 setValue : function(v){
40037 v = this.fixPrecision(v);
40038 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40042 decimalPrecisionFcn : function(v){
40043 return Math.floor(v);
40046 beforeBlur : function(){
40047 var v = this.parseValue(this.getRawValue());
40054 * Ext JS Library 1.1.1
40055 * Copyright(c) 2006-2007, Ext JS, LLC.
40057 * Originally Released Under LGPL - original licence link has changed is not relivant.
40060 * <script type="text/javascript">
40064 * @class Roo.form.DateField
40065 * @extends Roo.form.TriggerField
40066 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40068 * Create a new DateField
40069 * @param {Object} config
40071 Roo.form.DateField = function(config){
40072 Roo.form.DateField.superclass.constructor.call(this, config);
40078 * Fires when a date is selected
40079 * @param {Roo.form.DateField} combo This combo box
40080 * @param {Date} date The date selected
40087 if(typeof this.minValue == "string") {
40088 this.minValue = this.parseDate(this.minValue);
40090 if(typeof this.maxValue == "string") {
40091 this.maxValue = this.parseDate(this.maxValue);
40093 this.ddMatch = null;
40094 if(this.disabledDates){
40095 var dd = this.disabledDates;
40097 for(var i = 0; i < dd.length; i++){
40099 if(i != dd.length-1) {
40103 this.ddMatch = new RegExp(re + ")");
40107 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40109 * @cfg {String} format
40110 * The default date format string which can be overriden for localization support. The format must be
40111 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40115 * @cfg {String} altFormats
40116 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40117 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40119 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40121 * @cfg {Array} disabledDays
40122 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40124 disabledDays : null,
40126 * @cfg {String} disabledDaysText
40127 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40129 disabledDaysText : "Disabled",
40131 * @cfg {Array} disabledDates
40132 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40133 * expression so they are very powerful. Some examples:
40135 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40136 * <li>["03/08", "09/16"] would disable those days for every year</li>
40137 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40138 * <li>["03/../2006"] would disable every day in March 2006</li>
40139 * <li>["^03"] would disable every day in every March</li>
40141 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40142 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40144 disabledDates : null,
40146 * @cfg {String} disabledDatesText
40147 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40149 disabledDatesText : "Disabled",
40151 * @cfg {Date/String} minValue
40152 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40153 * valid format (defaults to null).
40157 * @cfg {Date/String} maxValue
40158 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40159 * valid format (defaults to null).
40163 * @cfg {String} minText
40164 * The error text to display when the date in the cell is before minValue (defaults to
40165 * 'The date in this field must be after {minValue}').
40167 minText : "The date in this field must be equal to or after {0}",
40169 * @cfg {String} maxText
40170 * The error text to display when the date in the cell is after maxValue (defaults to
40171 * 'The date in this field must be before {maxValue}').
40173 maxText : "The date in this field must be equal to or before {0}",
40175 * @cfg {String} invalidText
40176 * The error text to display when the date in the field is invalid (defaults to
40177 * '{value} is not a valid date - it must be in the format {format}').
40179 invalidText : "{0} is not a valid date - it must be in the format {1}",
40181 * @cfg {String} triggerClass
40182 * An additional CSS class used to style the trigger button. The trigger will always get the
40183 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40184 * which displays a calendar icon).
40186 triggerClass : 'x-form-date-trigger',
40190 * @cfg {Boolean} useIso
40191 * if enabled, then the date field will use a hidden field to store the
40192 * real value as iso formated date. default (false)
40196 * @cfg {String/Object} autoCreate
40197 * A DomHelper element spec, or true for a default element spec (defaults to
40198 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40201 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40204 hiddenField: false,
40206 onRender : function(ct, position)
40208 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40210 //this.el.dom.removeAttribute('name');
40211 Roo.log("Changing name?");
40212 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40213 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40215 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40216 // prevent input submission
40217 this.hiddenName = this.name;
40224 validateValue : function(value)
40226 value = this.formatDate(value);
40227 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40228 Roo.log('super failed');
40231 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40234 var svalue = value;
40235 value = this.parseDate(value);
40237 Roo.log('parse date failed' + svalue);
40238 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40241 var time = value.getTime();
40242 if(this.minValue && time < this.minValue.getTime()){
40243 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40246 if(this.maxValue && time > this.maxValue.getTime()){
40247 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40250 if(this.disabledDays){
40251 var day = value.getDay();
40252 for(var i = 0; i < this.disabledDays.length; i++) {
40253 if(day === this.disabledDays[i]){
40254 this.markInvalid(this.disabledDaysText);
40259 var fvalue = this.formatDate(value);
40260 if(this.ddMatch && this.ddMatch.test(fvalue)){
40261 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40268 // Provides logic to override the default TriggerField.validateBlur which just returns true
40269 validateBlur : function(){
40270 return !this.menu || !this.menu.isVisible();
40273 getName: function()
40275 // returns hidden if it's set..
40276 if (!this.rendered) {return ''};
40277 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40282 * Returns the current date value of the date field.
40283 * @return {Date} The date value
40285 getValue : function(){
40287 return this.hiddenField ?
40288 this.hiddenField.value :
40289 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40293 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40294 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40295 * (the default format used is "m/d/y").
40298 //All of these calls set the same date value (May 4, 2006)
40300 //Pass a date object:
40301 var dt = new Date('5/4/06');
40302 dateField.setValue(dt);
40304 //Pass a date string (default format):
40305 dateField.setValue('5/4/06');
40307 //Pass a date string (custom format):
40308 dateField.format = 'Y-m-d';
40309 dateField.setValue('2006-5-4');
40311 * @param {String/Date} date The date or valid date string
40313 setValue : function(date){
40314 if (this.hiddenField) {
40315 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40317 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40318 // make sure the value field is always stored as a date..
40319 this.value = this.parseDate(date);
40325 parseDate : function(value){
40326 if(!value || value instanceof Date){
40329 var v = Date.parseDate(value, this.format);
40330 if (!v && this.useIso) {
40331 v = Date.parseDate(value, 'Y-m-d');
40333 if(!v && this.altFormats){
40334 if(!this.altFormatsArray){
40335 this.altFormatsArray = this.altFormats.split("|");
40337 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40338 v = Date.parseDate(value, this.altFormatsArray[i]);
40345 formatDate : function(date, fmt){
40346 return (!date || !(date instanceof Date)) ?
40347 date : date.dateFormat(fmt || this.format);
40352 select: function(m, d){
40355 this.fireEvent('select', this, d);
40357 show : function(){ // retain focus styling
40361 this.focus.defer(10, this);
40362 var ml = this.menuListeners;
40363 this.menu.un("select", ml.select, this);
40364 this.menu.un("show", ml.show, this);
40365 this.menu.un("hide", ml.hide, this);
40370 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40371 onTriggerClick : function(){
40375 if(this.menu == null){
40376 this.menu = new Roo.menu.DateMenu();
40378 Roo.apply(this.menu.picker, {
40379 showClear: this.allowBlank,
40380 minDate : this.minValue,
40381 maxDate : this.maxValue,
40382 disabledDatesRE : this.ddMatch,
40383 disabledDatesText : this.disabledDatesText,
40384 disabledDays : this.disabledDays,
40385 disabledDaysText : this.disabledDaysText,
40386 format : this.useIso ? 'Y-m-d' : this.format,
40387 minText : String.format(this.minText, this.formatDate(this.minValue)),
40388 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40390 this.menu.on(Roo.apply({}, this.menuListeners, {
40393 this.menu.picker.setValue(this.getValue() || new Date());
40394 this.menu.show(this.el, "tl-bl?");
40397 beforeBlur : function(){
40398 var v = this.parseDate(this.getRawValue());
40408 isDirty : function() {
40409 if(this.disabled) {
40413 if(typeof(this.startValue) === 'undefined'){
40417 return String(this.getValue()) !== String(this.startValue);
40422 * Ext JS Library 1.1.1
40423 * Copyright(c) 2006-2007, Ext JS, LLC.
40425 * Originally Released Under LGPL - original licence link has changed is not relivant.
40428 * <script type="text/javascript">
40432 * @class Roo.form.MonthField
40433 * @extends Roo.form.TriggerField
40434 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40436 * Create a new MonthField
40437 * @param {Object} config
40439 Roo.form.MonthField = function(config){
40441 Roo.form.MonthField.superclass.constructor.call(this, config);
40447 * Fires when a date is selected
40448 * @param {Roo.form.MonthFieeld} combo This combo box
40449 * @param {Date} date The date selected
40456 if(typeof this.minValue == "string") {
40457 this.minValue = this.parseDate(this.minValue);
40459 if(typeof this.maxValue == "string") {
40460 this.maxValue = this.parseDate(this.maxValue);
40462 this.ddMatch = null;
40463 if(this.disabledDates){
40464 var dd = this.disabledDates;
40466 for(var i = 0; i < dd.length; i++){
40468 if(i != dd.length-1) {
40472 this.ddMatch = new RegExp(re + ")");
40476 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40478 * @cfg {String} format
40479 * The default date format string which can be overriden for localization support. The format must be
40480 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40484 * @cfg {String} altFormats
40485 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40486 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40488 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40490 * @cfg {Array} disabledDays
40491 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40493 disabledDays : [0,1,2,3,4,5,6],
40495 * @cfg {String} disabledDaysText
40496 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40498 disabledDaysText : "Disabled",
40500 * @cfg {Array} disabledDates
40501 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40502 * expression so they are very powerful. Some examples:
40504 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40505 * <li>["03/08", "09/16"] would disable those days for every year</li>
40506 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40507 * <li>["03/../2006"] would disable every day in March 2006</li>
40508 * <li>["^03"] would disable every day in every March</li>
40510 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40511 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40513 disabledDates : null,
40515 * @cfg {String} disabledDatesText
40516 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40518 disabledDatesText : "Disabled",
40520 * @cfg {Date/String} minValue
40521 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40522 * valid format (defaults to null).
40526 * @cfg {Date/String} maxValue
40527 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40528 * valid format (defaults to null).
40532 * @cfg {String} minText
40533 * The error text to display when the date in the cell is before minValue (defaults to
40534 * 'The date in this field must be after {minValue}').
40536 minText : "The date in this field must be equal to or after {0}",
40538 * @cfg {String} maxTextf
40539 * The error text to display when the date in the cell is after maxValue (defaults to
40540 * 'The date in this field must be before {maxValue}').
40542 maxText : "The date in this field must be equal to or before {0}",
40544 * @cfg {String} invalidText
40545 * The error text to display when the date in the field is invalid (defaults to
40546 * '{value} is not a valid date - it must be in the format {format}').
40548 invalidText : "{0} is not a valid date - it must be in the format {1}",
40550 * @cfg {String} triggerClass
40551 * An additional CSS class used to style the trigger button. The trigger will always get the
40552 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40553 * which displays a calendar icon).
40555 triggerClass : 'x-form-date-trigger',
40559 * @cfg {Boolean} useIso
40560 * if enabled, then the date field will use a hidden field to store the
40561 * real value as iso formated date. default (true)
40565 * @cfg {String/Object} autoCreate
40566 * A DomHelper element spec, or true for a default element spec (defaults to
40567 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40570 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40573 hiddenField: false,
40575 hideMonthPicker : false,
40577 onRender : function(ct, position)
40579 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40581 this.el.dom.removeAttribute('name');
40582 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40584 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40585 // prevent input submission
40586 this.hiddenName = this.name;
40593 validateValue : function(value)
40595 value = this.formatDate(value);
40596 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40599 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40602 var svalue = value;
40603 value = this.parseDate(value);
40605 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40608 var time = value.getTime();
40609 if(this.minValue && time < this.minValue.getTime()){
40610 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40613 if(this.maxValue && time > this.maxValue.getTime()){
40614 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40617 /*if(this.disabledDays){
40618 var day = value.getDay();
40619 for(var i = 0; i < this.disabledDays.length; i++) {
40620 if(day === this.disabledDays[i]){
40621 this.markInvalid(this.disabledDaysText);
40627 var fvalue = this.formatDate(value);
40628 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40629 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40637 // Provides logic to override the default TriggerField.validateBlur which just returns true
40638 validateBlur : function(){
40639 return !this.menu || !this.menu.isVisible();
40643 * Returns the current date value of the date field.
40644 * @return {Date} The date value
40646 getValue : function(){
40650 return this.hiddenField ?
40651 this.hiddenField.value :
40652 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40656 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40657 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40658 * (the default format used is "m/d/y").
40661 //All of these calls set the same date value (May 4, 2006)
40663 //Pass a date object:
40664 var dt = new Date('5/4/06');
40665 monthField.setValue(dt);
40667 //Pass a date string (default format):
40668 monthField.setValue('5/4/06');
40670 //Pass a date string (custom format):
40671 monthField.format = 'Y-m-d';
40672 monthField.setValue('2006-5-4');
40674 * @param {String/Date} date The date or valid date string
40676 setValue : function(date){
40677 Roo.log('month setValue' + date);
40678 // can only be first of month..
40680 var val = this.parseDate(date);
40682 if (this.hiddenField) {
40683 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40685 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40686 this.value = this.parseDate(date);
40690 parseDate : function(value){
40691 if(!value || value instanceof Date){
40692 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40695 var v = Date.parseDate(value, this.format);
40696 if (!v && this.useIso) {
40697 v = Date.parseDate(value, 'Y-m-d');
40701 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40705 if(!v && this.altFormats){
40706 if(!this.altFormatsArray){
40707 this.altFormatsArray = this.altFormats.split("|");
40709 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40710 v = Date.parseDate(value, this.altFormatsArray[i]);
40717 formatDate : function(date, fmt){
40718 return (!date || !(date instanceof Date)) ?
40719 date : date.dateFormat(fmt || this.format);
40724 select: function(m, d){
40726 this.fireEvent('select', this, d);
40728 show : function(){ // retain focus styling
40732 this.focus.defer(10, this);
40733 var ml = this.menuListeners;
40734 this.menu.un("select", ml.select, this);
40735 this.menu.un("show", ml.show, this);
40736 this.menu.un("hide", ml.hide, this);
40740 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40741 onTriggerClick : function(){
40745 if(this.menu == null){
40746 this.menu = new Roo.menu.DateMenu();
40750 Roo.apply(this.menu.picker, {
40752 showClear: this.allowBlank,
40753 minDate : this.minValue,
40754 maxDate : this.maxValue,
40755 disabledDatesRE : this.ddMatch,
40756 disabledDatesText : this.disabledDatesText,
40758 format : this.useIso ? 'Y-m-d' : this.format,
40759 minText : String.format(this.minText, this.formatDate(this.minValue)),
40760 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40763 this.menu.on(Roo.apply({}, this.menuListeners, {
40771 // hide month picker get's called when we called by 'before hide';
40773 var ignorehide = true;
40774 p.hideMonthPicker = function(disableAnim){
40778 if(this.monthPicker){
40779 Roo.log("hideMonthPicker called");
40780 if(disableAnim === true){
40781 this.monthPicker.hide();
40783 this.monthPicker.slideOut('t', {duration:.2});
40784 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40785 p.fireEvent("select", this, this.value);
40791 Roo.log('picker set value');
40792 Roo.log(this.getValue());
40793 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40794 m.show(this.el, 'tl-bl?');
40795 ignorehide = false;
40796 // this will trigger hideMonthPicker..
40799 // hidden the day picker
40800 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40806 p.showMonthPicker.defer(100, p);
40812 beforeBlur : function(){
40813 var v = this.parseDate(this.getRawValue());
40819 /** @cfg {Boolean} grow @hide */
40820 /** @cfg {Number} growMin @hide */
40821 /** @cfg {Number} growMax @hide */
40828 * Ext JS Library 1.1.1
40829 * Copyright(c) 2006-2007, Ext JS, LLC.
40831 * Originally Released Under LGPL - original licence link has changed is not relivant.
40834 * <script type="text/javascript">
40839 * @class Roo.form.ComboBox
40840 * @extends Roo.form.TriggerField
40841 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40843 * Create a new ComboBox.
40844 * @param {Object} config Configuration options
40846 Roo.form.ComboBox = function(config){
40847 Roo.form.ComboBox.superclass.constructor.call(this, config);
40851 * Fires when the dropdown list is expanded
40852 * @param {Roo.form.ComboBox} combo This combo box
40857 * Fires when the dropdown list is collapsed
40858 * @param {Roo.form.ComboBox} combo This combo box
40862 * @event beforeselect
40863 * Fires before a list item is selected. Return false to cancel the selection.
40864 * @param {Roo.form.ComboBox} combo This combo box
40865 * @param {Roo.data.Record} record The data record returned from the underlying store
40866 * @param {Number} index The index of the selected item in the dropdown list
40868 'beforeselect' : true,
40871 * Fires when a list item is selected
40872 * @param {Roo.form.ComboBox} combo This combo box
40873 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40874 * @param {Number} index The index of the selected item in the dropdown list
40878 * @event beforequery
40879 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40880 * The event object passed has these properties:
40881 * @param {Roo.form.ComboBox} combo This combo box
40882 * @param {String} query The query
40883 * @param {Boolean} forceAll true to force "all" query
40884 * @param {Boolean} cancel true to cancel the query
40885 * @param {Object} e The query event object
40887 'beforequery': true,
40890 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40891 * @param {Roo.form.ComboBox} combo This combo box
40896 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40897 * @param {Roo.form.ComboBox} combo This combo box
40898 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40904 if(this.transform){
40905 this.allowDomMove = false;
40906 var s = Roo.getDom(this.transform);
40907 if(!this.hiddenName){
40908 this.hiddenName = s.name;
40911 this.mode = 'local';
40912 var d = [], opts = s.options;
40913 for(var i = 0, len = opts.length;i < len; i++){
40915 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40917 this.value = value;
40919 d.push([value, o.text]);
40921 this.store = new Roo.data.SimpleStore({
40923 fields: ['value', 'text'],
40926 this.valueField = 'value';
40927 this.displayField = 'text';
40929 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40930 if(!this.lazyRender){
40931 this.target = true;
40932 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40933 s.parentNode.removeChild(s); // remove it
40934 this.render(this.el.parentNode);
40936 s.parentNode.removeChild(s); // remove it
40941 this.store = Roo.factory(this.store, Roo.data);
40944 this.selectedIndex = -1;
40945 if(this.mode == 'local'){
40946 if(config.queryDelay === undefined){
40947 this.queryDelay = 10;
40949 if(config.minChars === undefined){
40955 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40957 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40960 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40961 * rendering into an Roo.Editor, defaults to false)
40964 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40965 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40968 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40971 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40972 * the dropdown list (defaults to undefined, with no header element)
40976 * @cfg {String/Roo.Template} tpl The template to use to render the output
40980 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40982 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40984 listWidth: undefined,
40986 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40987 * mode = 'remote' or 'text' if mode = 'local')
40989 displayField: undefined,
40991 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40992 * mode = 'remote' or 'value' if mode = 'local').
40993 * Note: use of a valueField requires the user make a selection
40994 * in order for a value to be mapped.
40996 valueField: undefined,
41000 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41001 * field's data value (defaults to the underlying DOM element's name)
41003 hiddenName: undefined,
41005 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41009 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41011 selectedClass: 'x-combo-selected',
41013 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41014 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41015 * which displays a downward arrow icon).
41017 triggerClass : 'x-form-arrow-trigger',
41019 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41023 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41024 * anchor positions (defaults to 'tl-bl')
41026 listAlign: 'tl-bl?',
41028 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41032 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41033 * query specified by the allQuery config option (defaults to 'query')
41035 triggerAction: 'query',
41037 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41038 * (defaults to 4, does not apply if editable = false)
41042 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41043 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41047 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41048 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41052 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41053 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41057 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41058 * when editable = true (defaults to false)
41060 selectOnFocus:false,
41062 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41064 queryParam: 'query',
41066 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41067 * when mode = 'remote' (defaults to 'Loading...')
41069 loadingText: 'Loading...',
41071 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41075 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41079 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41080 * traditional select (defaults to true)
41084 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41088 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41092 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41093 * listWidth has a higher value)
41097 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41098 * allow the user to set arbitrary text into the field (defaults to false)
41100 forceSelection:false,
41102 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41103 * if typeAhead = true (defaults to 250)
41105 typeAheadDelay : 250,
41107 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41108 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41110 valueNotFoundText : undefined,
41112 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41114 blockFocus : false,
41117 * @cfg {Boolean} disableClear Disable showing of clear button.
41119 disableClear : false,
41121 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41123 alwaysQuery : false,
41129 // element that contains real text value.. (when hidden is used..)
41132 onRender : function(ct, position){
41133 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41134 if(this.hiddenName){
41135 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41137 this.hiddenField.value =
41138 this.hiddenValue !== undefined ? this.hiddenValue :
41139 this.value !== undefined ? this.value : '';
41141 // prevent input submission
41142 this.el.dom.removeAttribute('name');
41147 this.el.dom.setAttribute('autocomplete', 'off');
41150 var cls = 'x-combo-list';
41152 this.list = new Roo.Layer({
41153 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41156 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41157 this.list.setWidth(lw);
41158 this.list.swallowEvent('mousewheel');
41159 this.assetHeight = 0;
41162 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41163 this.assetHeight += this.header.getHeight();
41166 this.innerList = this.list.createChild({cls:cls+'-inner'});
41167 this.innerList.on('mouseover', this.onViewOver, this);
41168 this.innerList.on('mousemove', this.onViewMove, this);
41169 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41171 if(this.allowBlank && !this.pageSize && !this.disableClear){
41172 this.footer = this.list.createChild({cls:cls+'-ft'});
41173 this.pageTb = new Roo.Toolbar(this.footer);
41177 this.footer = this.list.createChild({cls:cls+'-ft'});
41178 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41179 {pageSize: this.pageSize});
41183 if (this.pageTb && this.allowBlank && !this.disableClear) {
41185 this.pageTb.add(new Roo.Toolbar.Fill(), {
41186 cls: 'x-btn-icon x-btn-clear',
41188 handler: function()
41191 _this.clearValue();
41192 _this.onSelect(false, -1);
41197 this.assetHeight += this.footer.getHeight();
41202 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41205 this.view = new Roo.View(this.innerList, this.tpl, {
41206 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41209 this.view.on('click', this.onViewClick, this);
41211 this.store.on('beforeload', this.onBeforeLoad, this);
41212 this.store.on('load', this.onLoad, this);
41213 this.store.on('loadexception', this.onLoadException, this);
41215 if(this.resizable){
41216 this.resizer = new Roo.Resizable(this.list, {
41217 pinned:true, handles:'se'
41219 this.resizer.on('resize', function(r, w, h){
41220 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41221 this.listWidth = w;
41222 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41223 this.restrictHeight();
41225 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41227 if(!this.editable){
41228 this.editable = true;
41229 this.setEditable(false);
41233 if (typeof(this.events.add.listeners) != 'undefined') {
41235 this.addicon = this.wrap.createChild(
41236 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41238 this.addicon.on('click', function(e) {
41239 this.fireEvent('add', this);
41242 if (typeof(this.events.edit.listeners) != 'undefined') {
41244 this.editicon = this.wrap.createChild(
41245 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41246 if (this.addicon) {
41247 this.editicon.setStyle('margin-left', '40px');
41249 this.editicon.on('click', function(e) {
41251 // we fire even if inothing is selected..
41252 this.fireEvent('edit', this, this.lastData );
41262 initEvents : function(){
41263 Roo.form.ComboBox.superclass.initEvents.call(this);
41265 this.keyNav = new Roo.KeyNav(this.el, {
41266 "up" : function(e){
41267 this.inKeyMode = true;
41271 "down" : function(e){
41272 if(!this.isExpanded()){
41273 this.onTriggerClick();
41275 this.inKeyMode = true;
41280 "enter" : function(e){
41281 this.onViewClick();
41285 "esc" : function(e){
41289 "tab" : function(e){
41290 this.onViewClick(false);
41291 this.fireEvent("specialkey", this, e);
41297 doRelay : function(foo, bar, hname){
41298 if(hname == 'down' || this.scope.isExpanded()){
41299 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41306 this.queryDelay = Math.max(this.queryDelay || 10,
41307 this.mode == 'local' ? 10 : 250);
41308 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41309 if(this.typeAhead){
41310 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41312 if(this.editable !== false){
41313 this.el.on("keyup", this.onKeyUp, this);
41315 if(this.forceSelection){
41316 this.on('blur', this.doForce, this);
41320 onDestroy : function(){
41322 this.view.setStore(null);
41323 this.view.el.removeAllListeners();
41324 this.view.el.remove();
41325 this.view.purgeListeners();
41328 this.list.destroy();
41331 this.store.un('beforeload', this.onBeforeLoad, this);
41332 this.store.un('load', this.onLoad, this);
41333 this.store.un('loadexception', this.onLoadException, this);
41335 Roo.form.ComboBox.superclass.onDestroy.call(this);
41339 fireKey : function(e){
41340 if(e.isNavKeyPress() && !this.list.isVisible()){
41341 this.fireEvent("specialkey", this, e);
41346 onResize: function(w, h){
41347 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41349 if(typeof w != 'number'){
41350 // we do not handle it!?!?
41353 var tw = this.trigger.getWidth();
41354 tw += this.addicon ? this.addicon.getWidth() : 0;
41355 tw += this.editicon ? this.editicon.getWidth() : 0;
41357 this.el.setWidth( this.adjustWidth('input', x));
41359 this.trigger.setStyle('left', x+'px');
41361 if(this.list && this.listWidth === undefined){
41362 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41363 this.list.setWidth(lw);
41364 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41372 * Allow or prevent the user from directly editing the field text. If false is passed,
41373 * the user will only be able to select from the items defined in the dropdown list. This method
41374 * is the runtime equivalent of setting the 'editable' config option at config time.
41375 * @param {Boolean} value True to allow the user to directly edit the field text
41377 setEditable : function(value){
41378 if(value == this.editable){
41381 this.editable = value;
41383 this.el.dom.setAttribute('readOnly', true);
41384 this.el.on('mousedown', this.onTriggerClick, this);
41385 this.el.addClass('x-combo-noedit');
41387 this.el.dom.setAttribute('readOnly', false);
41388 this.el.un('mousedown', this.onTriggerClick, this);
41389 this.el.removeClass('x-combo-noedit');
41394 onBeforeLoad : function(){
41395 if(!this.hasFocus){
41398 this.innerList.update(this.loadingText ?
41399 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41400 this.restrictHeight();
41401 this.selectedIndex = -1;
41405 onLoad : function(){
41406 if(!this.hasFocus){
41409 if(this.store.getCount() > 0){
41411 this.restrictHeight();
41412 if(this.lastQuery == this.allQuery){
41414 this.el.dom.select();
41416 if(!this.selectByValue(this.value, true)){
41417 this.select(0, true);
41421 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41422 this.taTask.delay(this.typeAheadDelay);
41426 this.onEmptyResults();
41431 onLoadException : function()
41434 Roo.log(this.store.reader.jsonData);
41435 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41436 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41442 onTypeAhead : function(){
41443 if(this.store.getCount() > 0){
41444 var r = this.store.getAt(0);
41445 var newValue = r.data[this.displayField];
41446 var len = newValue.length;
41447 var selStart = this.getRawValue().length;
41448 if(selStart != len){
41449 this.setRawValue(newValue);
41450 this.selectText(selStart, newValue.length);
41456 onSelect : function(record, index){
41457 if(this.fireEvent('beforeselect', this, record, index) !== false){
41458 this.setFromData(index > -1 ? record.data : false);
41460 this.fireEvent('select', this, record, index);
41465 * Returns the currently selected field value or empty string if no value is set.
41466 * @return {String} value The selected value
41468 getValue : function(){
41469 if(this.valueField){
41470 return typeof this.value != 'undefined' ? this.value : '';
41472 return Roo.form.ComboBox.superclass.getValue.call(this);
41476 * Clears any text/value currently set in the field
41478 clearValue : function(){
41479 if(this.hiddenField){
41480 this.hiddenField.value = '';
41483 this.setRawValue('');
41484 this.lastSelectionText = '';
41489 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41490 * will be displayed in the field. If the value does not match the data value of an existing item,
41491 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41492 * Otherwise the field will be blank (although the value will still be set).
41493 * @param {String} value The value to match
41495 setValue : function(v){
41497 if(this.valueField){
41498 var r = this.findRecord(this.valueField, v);
41500 text = r.data[this.displayField];
41501 }else if(this.valueNotFoundText !== undefined){
41502 text = this.valueNotFoundText;
41505 this.lastSelectionText = text;
41506 if(this.hiddenField){
41507 this.hiddenField.value = v;
41509 Roo.form.ComboBox.superclass.setValue.call(this, text);
41513 * @property {Object} the last set data for the element
41518 * Sets the value of the field based on a object which is related to the record format for the store.
41519 * @param {Object} value the value to set as. or false on reset?
41521 setFromData : function(o){
41522 var dv = ''; // display value
41523 var vv = ''; // value value..
41525 if (this.displayField) {
41526 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41528 // this is an error condition!!!
41529 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41532 if(this.valueField){
41533 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41535 if(this.hiddenField){
41536 this.hiddenField.value = vv;
41538 this.lastSelectionText = dv;
41539 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41543 // no hidden field.. - we store the value in 'value', but still display
41544 // display field!!!!
41545 this.lastSelectionText = dv;
41546 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41552 reset : function(){
41553 // overridden so that last data is reset..
41554 this.setValue(this.resetValue);
41555 this.clearInvalid();
41556 this.lastData = false;
41558 this.view.clearSelections();
41562 findRecord : function(prop, value){
41564 if(this.store.getCount() > 0){
41565 this.store.each(function(r){
41566 if(r.data[prop] == value){
41576 getName: function()
41578 // returns hidden if it's set..
41579 if (!this.rendered) {return ''};
41580 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41584 onViewMove : function(e, t){
41585 this.inKeyMode = false;
41589 onViewOver : function(e, t){
41590 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41593 var item = this.view.findItemFromChild(t);
41595 var index = this.view.indexOf(item);
41596 this.select(index, false);
41601 onViewClick : function(doFocus)
41603 var index = this.view.getSelectedIndexes()[0];
41604 var r = this.store.getAt(index);
41606 this.onSelect(r, index);
41608 if(doFocus !== false && !this.blockFocus){
41614 restrictHeight : function(){
41615 this.innerList.dom.style.height = '';
41616 var inner = this.innerList.dom;
41617 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41618 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41619 this.list.beginUpdate();
41620 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41621 this.list.alignTo(this.el, this.listAlign);
41622 this.list.endUpdate();
41626 onEmptyResults : function(){
41631 * Returns true if the dropdown list is expanded, else false.
41633 isExpanded : function(){
41634 return this.list.isVisible();
41638 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41639 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41640 * @param {String} value The data value of the item to select
41641 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41642 * selected item if it is not currently in view (defaults to true)
41643 * @return {Boolean} True if the value matched an item in the list, else false
41645 selectByValue : function(v, scrollIntoView){
41646 if(v !== undefined && v !== null){
41647 var r = this.findRecord(this.valueField || this.displayField, v);
41649 this.select(this.store.indexOf(r), scrollIntoView);
41657 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41658 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41659 * @param {Number} index The zero-based index of the list item to select
41660 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41661 * selected item if it is not currently in view (defaults to true)
41663 select : function(index, scrollIntoView){
41664 this.selectedIndex = index;
41665 this.view.select(index);
41666 if(scrollIntoView !== false){
41667 var el = this.view.getNode(index);
41669 this.innerList.scrollChildIntoView(el, false);
41675 selectNext : function(){
41676 var ct = this.store.getCount();
41678 if(this.selectedIndex == -1){
41680 }else if(this.selectedIndex < ct-1){
41681 this.select(this.selectedIndex+1);
41687 selectPrev : function(){
41688 var ct = this.store.getCount();
41690 if(this.selectedIndex == -1){
41692 }else if(this.selectedIndex != 0){
41693 this.select(this.selectedIndex-1);
41699 onKeyUp : function(e){
41700 if(this.editable !== false && !e.isSpecialKey()){
41701 this.lastKey = e.getKey();
41702 this.dqTask.delay(this.queryDelay);
41707 validateBlur : function(){
41708 return !this.list || !this.list.isVisible();
41712 initQuery : function(){
41713 this.doQuery(this.getRawValue());
41717 doForce : function(){
41718 if(this.el.dom.value.length > 0){
41719 this.el.dom.value =
41720 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41726 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41727 * query allowing the query action to be canceled if needed.
41728 * @param {String} query The SQL query to execute
41729 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41730 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41731 * saved in the current store (defaults to false)
41733 doQuery : function(q, forceAll){
41734 if(q === undefined || q === null){
41739 forceAll: forceAll,
41743 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41747 forceAll = qe.forceAll;
41748 if(forceAll === true || (q.length >= this.minChars)){
41749 if(this.lastQuery != q || this.alwaysQuery){
41750 this.lastQuery = q;
41751 if(this.mode == 'local'){
41752 this.selectedIndex = -1;
41754 this.store.clearFilter();
41756 this.store.filter(this.displayField, q);
41760 this.store.baseParams[this.queryParam] = q;
41762 params: this.getParams(q)
41767 this.selectedIndex = -1;
41774 getParams : function(q){
41776 //p[this.queryParam] = q;
41779 p.limit = this.pageSize;
41785 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41787 collapse : function(){
41788 if(!this.isExpanded()){
41792 Roo.get(document).un('mousedown', this.collapseIf, this);
41793 Roo.get(document).un('mousewheel', this.collapseIf, this);
41794 if (!this.editable) {
41795 Roo.get(document).un('keydown', this.listKeyPress, this);
41797 this.fireEvent('collapse', this);
41801 collapseIf : function(e){
41802 if(!e.within(this.wrap) && !e.within(this.list)){
41808 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41810 expand : function(){
41811 if(this.isExpanded() || !this.hasFocus){
41814 this.list.alignTo(this.el, this.listAlign);
41816 Roo.get(document).on('mousedown', this.collapseIf, this);
41817 Roo.get(document).on('mousewheel', this.collapseIf, this);
41818 if (!this.editable) {
41819 Roo.get(document).on('keydown', this.listKeyPress, this);
41822 this.fireEvent('expand', this);
41826 // Implements the default empty TriggerField.onTriggerClick function
41827 onTriggerClick : function(){
41831 if(this.isExpanded()){
41833 if (!this.blockFocus) {
41838 this.hasFocus = true;
41839 if(this.triggerAction == 'all') {
41840 this.doQuery(this.allQuery, true);
41842 this.doQuery(this.getRawValue());
41844 if (!this.blockFocus) {
41849 listKeyPress : function(e)
41851 //Roo.log('listkeypress');
41852 // scroll to first matching element based on key pres..
41853 if (e.isSpecialKey()) {
41856 var k = String.fromCharCode(e.getKey()).toUpperCase();
41859 var csel = this.view.getSelectedNodes();
41860 var cselitem = false;
41862 var ix = this.view.indexOf(csel[0]);
41863 cselitem = this.store.getAt(ix);
41864 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41870 this.store.each(function(v) {
41872 // start at existing selection.
41873 if (cselitem.id == v.id) {
41879 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41880 match = this.store.indexOf(v);
41885 if (match === false) {
41886 return true; // no more action?
41889 this.view.select(match);
41890 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41891 sn.scrollIntoView(sn.dom.parentNode, false);
41895 * @cfg {Boolean} grow
41899 * @cfg {Number} growMin
41903 * @cfg {Number} growMax
41911 * Copyright(c) 2010-2012, Roo J Solutions Limited
41918 * @class Roo.form.ComboBoxArray
41919 * @extends Roo.form.TextField
41920 * A facebook style adder... for lists of email / people / countries etc...
41921 * pick multiple items from a combo box, and shows each one.
41923 * Fred [x] Brian [x] [Pick another |v]
41926 * For this to work: it needs various extra information
41927 * - normal combo problay has
41929 * + displayField, valueField
41931 * For our purpose...
41934 * If we change from 'extends' to wrapping...
41941 * Create a new ComboBoxArray.
41942 * @param {Object} config Configuration options
41946 Roo.form.ComboBoxArray = function(config)
41950 * @event beforeremove
41951 * Fires before remove the value from the list
41952 * @param {Roo.form.ComboBoxArray} _self This combo box array
41953 * @param {Roo.form.ComboBoxArray.Item} item removed item
41955 'beforeremove' : true,
41958 * Fires when remove the value from the list
41959 * @param {Roo.form.ComboBoxArray} _self This combo box array
41960 * @param {Roo.form.ComboBoxArray.Item} item removed item
41967 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41969 this.items = new Roo.util.MixedCollection(false);
41971 // construct the child combo...
41981 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41984 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41989 // behavies liek a hiddne field
41990 inputType: 'hidden',
41992 * @cfg {Number} width The width of the box that displays the selected element
41999 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42003 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42005 hiddenName : false,
42008 // private the array of items that are displayed..
42010 // private - the hidden field el.
42012 // private - the filed el..
42015 //validateValue : function() { return true; }, // all values are ok!
42016 //onAddClick: function() { },
42018 onRender : function(ct, position)
42021 // create the standard hidden element
42022 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42025 // give fake names to child combo;
42026 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42027 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42029 this.combo = Roo.factory(this.combo, Roo.form);
42030 this.combo.onRender(ct, position);
42031 if (typeof(this.combo.width) != 'undefined') {
42032 this.combo.onResize(this.combo.width,0);
42035 this.combo.initEvents();
42037 // assigned so form know we need to do this..
42038 this.store = this.combo.store;
42039 this.valueField = this.combo.valueField;
42040 this.displayField = this.combo.displayField ;
42043 this.combo.wrap.addClass('x-cbarray-grp');
42045 var cbwrap = this.combo.wrap.createChild(
42046 {tag: 'div', cls: 'x-cbarray-cb'},
42051 this.hiddenEl = this.combo.wrap.createChild({
42052 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42054 this.el = this.combo.wrap.createChild({
42055 tag: 'input', type:'hidden' , name: this.name, value : ''
42057 // this.el.dom.removeAttribute("name");
42060 this.outerWrap = this.combo.wrap;
42061 this.wrap = cbwrap;
42063 this.outerWrap.setWidth(this.width);
42064 this.outerWrap.dom.removeChild(this.el.dom);
42066 this.wrap.dom.appendChild(this.el.dom);
42067 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42068 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42070 this.combo.trigger.setStyle('position','relative');
42071 this.combo.trigger.setStyle('left', '0px');
42072 this.combo.trigger.setStyle('top', '2px');
42074 this.combo.el.setStyle('vertical-align', 'text-bottom');
42076 //this.trigger.setStyle('vertical-align', 'top');
42078 // this should use the code from combo really... on('add' ....)
42082 this.adder = this.outerWrap.createChild(
42083 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42085 this.adder.on('click', function(e) {
42086 _t.fireEvent('adderclick', this, e);
42090 //this.adder.on('click', this.onAddClick, _t);
42093 this.combo.on('select', function(cb, rec, ix) {
42094 this.addItem(rec.data);
42097 cb.el.dom.value = '';
42098 //cb.lastData = rec.data;
42107 getName: function()
42109 // returns hidden if it's set..
42110 if (!this.rendered) {return ''};
42111 return this.hiddenName ? this.hiddenName : this.name;
42116 onResize: function(w, h){
42119 // not sure if this is needed..
42120 //this.combo.onResize(w,h);
42122 if(typeof w != 'number'){
42123 // we do not handle it!?!?
42126 var tw = this.combo.trigger.getWidth();
42127 tw += this.addicon ? this.addicon.getWidth() : 0;
42128 tw += this.editicon ? this.editicon.getWidth() : 0;
42130 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42132 this.combo.trigger.setStyle('left', '0px');
42134 if(this.list && this.listWidth === undefined){
42135 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42136 this.list.setWidth(lw);
42137 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42144 addItem: function(rec)
42146 var valueField = this.combo.valueField;
42147 var displayField = this.combo.displayField;
42148 if (this.items.indexOfKey(rec[valueField]) > -1) {
42149 //console.log("GOT " + rec.data.id);
42153 var x = new Roo.form.ComboBoxArray.Item({
42154 //id : rec[this.idField],
42156 displayField : displayField ,
42157 tipField : displayField ,
42161 this.items.add(rec[valueField],x);
42162 // add it before the element..
42163 this.updateHiddenEl();
42164 x.render(this.outerWrap, this.wrap.dom);
42165 // add the image handler..
42168 updateHiddenEl : function()
42171 if (!this.hiddenEl) {
42175 var idField = this.combo.valueField;
42177 this.items.each(function(f) {
42178 ar.push(f.data[idField]);
42181 this.hiddenEl.dom.value = ar.join(',');
42187 this.items.clear();
42189 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42193 this.el.dom.value = '';
42194 if (this.hiddenEl) {
42195 this.hiddenEl.dom.value = '';
42199 getValue: function()
42201 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42203 setValue: function(v) // not a valid action - must use addItems..
42210 if (this.store.isLocal && (typeof(v) == 'string')) {
42211 // then we can use the store to find the values..
42212 // comma seperated at present.. this needs to allow JSON based encoding..
42213 this.hiddenEl.value = v;
42215 Roo.each(v.split(','), function(k) {
42216 Roo.log("CHECK " + this.valueField + ',' + k);
42217 var li = this.store.query(this.valueField, k);
42222 add[this.valueField] = k;
42223 add[this.displayField] = li.item(0).data[this.displayField];
42229 if (typeof(v) == 'object' ) {
42230 // then let's assume it's an array of objects..
42231 Roo.each(v, function(l) {
42239 setFromData: function(v)
42241 // this recieves an object, if setValues is called.
42243 this.el.dom.value = v[this.displayField];
42244 this.hiddenEl.dom.value = v[this.valueField];
42245 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42248 var kv = v[this.valueField];
42249 var dv = v[this.displayField];
42250 kv = typeof(kv) != 'string' ? '' : kv;
42251 dv = typeof(dv) != 'string' ? '' : dv;
42254 var keys = kv.split(',');
42255 var display = dv.split(',');
42256 for (var i = 0 ; i < keys.length; i++) {
42259 add[this.valueField] = keys[i];
42260 add[this.displayField] = display[i];
42268 * Validates the combox array value
42269 * @return {Boolean} True if the value is valid, else false
42271 validate : function(){
42272 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42273 this.clearInvalid();
42279 validateValue : function(value){
42280 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42288 isDirty : function() {
42289 if(this.disabled) {
42294 var d = Roo.decode(String(this.originalValue));
42296 return String(this.getValue()) !== String(this.originalValue);
42299 var originalValue = [];
42301 for (var i = 0; i < d.length; i++){
42302 originalValue.push(d[i][this.valueField]);
42305 return String(this.getValue()) !== String(originalValue.join(','));
42314 * @class Roo.form.ComboBoxArray.Item
42315 * @extends Roo.BoxComponent
42316 * A selected item in the list
42317 * Fred [x] Brian [x] [Pick another |v]
42320 * Create a new item.
42321 * @param {Object} config Configuration options
42324 Roo.form.ComboBoxArray.Item = function(config) {
42325 config.id = Roo.id();
42326 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42329 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42332 displayField : false,
42336 defaultAutoCreate : {
42338 cls: 'x-cbarray-item',
42345 src : Roo.BLANK_IMAGE_URL ,
42353 onRender : function(ct, position)
42355 Roo.form.Field.superclass.onRender.call(this, ct, position);
42358 var cfg = this.getAutoCreate();
42359 this.el = ct.createChild(cfg, position);
42362 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42364 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42365 this.cb.renderer(this.data) :
42366 String.format('{0}',this.data[this.displayField]);
42369 this.el.child('div').dom.setAttribute('qtip',
42370 String.format('{0}',this.data[this.tipField])
42373 this.el.child('img').on('click', this.remove, this);
42377 remove : function()
42379 if(this.cb.disabled){
42383 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42384 this.cb.items.remove(this);
42385 this.el.child('img').un('click', this.remove, this);
42387 this.cb.updateHiddenEl();
42389 this.cb.fireEvent('remove', this.cb, this);
42395 * Ext JS Library 1.1.1
42396 * Copyright(c) 2006-2007, Ext JS, LLC.
42398 * Originally Released Under LGPL - original licence link has changed is not relivant.
42401 * <script type="text/javascript">
42404 * @class Roo.form.Checkbox
42405 * @extends Roo.form.Field
42406 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42408 * Creates a new Checkbox
42409 * @param {Object} config Configuration options
42411 Roo.form.Checkbox = function(config){
42412 Roo.form.Checkbox.superclass.constructor.call(this, config);
42416 * Fires when the checkbox is checked or unchecked.
42417 * @param {Roo.form.Checkbox} this This checkbox
42418 * @param {Boolean} checked The new checked value
42424 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42426 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42428 focusClass : undefined,
42430 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42432 fieldClass: "x-form-field",
42434 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42438 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42439 * {tag: "input", type: "checkbox", autocomplete: "off"})
42441 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42443 * @cfg {String} boxLabel The text that appears beside the checkbox
42447 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42451 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42453 valueOff: '0', // value when not checked..
42455 actionMode : 'viewEl',
42458 itemCls : 'x-menu-check-item x-form-item',
42459 groupClass : 'x-menu-group-item',
42460 inputType : 'hidden',
42463 inSetChecked: false, // check that we are not calling self...
42465 inputElement: false, // real input element?
42466 basedOn: false, // ????
42468 isFormField: true, // not sure where this is needed!!!!
42470 onResize : function(){
42471 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42472 if(!this.boxLabel){
42473 this.el.alignTo(this.wrap, 'c-c');
42477 initEvents : function(){
42478 Roo.form.Checkbox.superclass.initEvents.call(this);
42479 this.el.on("click", this.onClick, this);
42480 this.el.on("change", this.onClick, this);
42484 getResizeEl : function(){
42488 getPositionEl : function(){
42493 onRender : function(ct, position){
42494 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42496 if(this.inputValue !== undefined){
42497 this.el.dom.value = this.inputValue;
42500 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42501 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42502 var viewEl = this.wrap.createChild({
42503 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42504 this.viewEl = viewEl;
42505 this.wrap.on('click', this.onClick, this);
42507 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42508 this.el.on('propertychange', this.setFromHidden, this); //ie
42513 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42514 // viewEl.on('click', this.onClick, this);
42516 //if(this.checked){
42517 this.setChecked(this.checked);
42519 //this.checked = this.el.dom;
42525 initValue : Roo.emptyFn,
42528 * Returns the checked state of the checkbox.
42529 * @return {Boolean} True if checked, else false
42531 getValue : function(){
42533 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42535 return this.valueOff;
42540 onClick : function(){
42541 if (this.disabled) {
42544 this.setChecked(!this.checked);
42546 //if(this.el.dom.checked != this.checked){
42547 // this.setValue(this.el.dom.checked);
42552 * Sets the checked state of the checkbox.
42553 * On is always based on a string comparison between inputValue and the param.
42554 * @param {Boolean/String} value - the value to set
42555 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42557 setValue : function(v,suppressEvent){
42560 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42561 //if(this.el && this.el.dom){
42562 // this.el.dom.checked = this.checked;
42563 // this.el.dom.defaultChecked = this.checked;
42565 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42566 //this.fireEvent("check", this, this.checked);
42569 setChecked : function(state,suppressEvent)
42571 if (this.inSetChecked) {
42572 this.checked = state;
42578 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42580 this.checked = state;
42581 if(suppressEvent !== true){
42582 this.fireEvent('check', this, state);
42584 this.inSetChecked = true;
42585 this.el.dom.value = state ? this.inputValue : this.valueOff;
42586 this.inSetChecked = false;
42589 // handle setting of hidden value by some other method!!?!?
42590 setFromHidden: function()
42595 //console.log("SET FROM HIDDEN");
42596 //alert('setFrom hidden');
42597 this.setValue(this.el.dom.value);
42600 onDestroy : function()
42603 Roo.get(this.viewEl).remove();
42606 Roo.form.Checkbox.superclass.onDestroy.call(this);
42609 setBoxLabel : function(str)
42611 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42616 * Ext JS Library 1.1.1
42617 * Copyright(c) 2006-2007, Ext JS, LLC.
42619 * Originally Released Under LGPL - original licence link has changed is not relivant.
42622 * <script type="text/javascript">
42626 * @class Roo.form.Radio
42627 * @extends Roo.form.Checkbox
42628 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42629 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42631 * Creates a new Radio
42632 * @param {Object} config Configuration options
42634 Roo.form.Radio = function(){
42635 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42637 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42638 inputType: 'radio',
42641 * If this radio is part of a group, it will return the selected value
42644 getGroupValue : function(){
42645 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42649 onRender : function(ct, position){
42650 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42652 if(this.inputValue !== undefined){
42653 this.el.dom.value = this.inputValue;
42656 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42657 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42658 //var viewEl = this.wrap.createChild({
42659 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42660 //this.viewEl = viewEl;
42661 //this.wrap.on('click', this.onClick, this);
42663 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42664 //this.el.on('propertychange', this.setFromHidden, this); //ie
42669 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42670 // viewEl.on('click', this.onClick, this);
42673 this.el.dom.checked = 'checked' ;
42679 });//<script type="text/javascript">
42682 * Based Ext JS Library 1.1.1
42683 * Copyright(c) 2006-2007, Ext JS, LLC.
42689 * @class Roo.HtmlEditorCore
42690 * @extends Roo.Component
42691 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42693 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42696 Roo.HtmlEditorCore = function(config){
42699 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42704 * @event initialize
42705 * Fires when the editor is fully initialized (including the iframe)
42706 * @param {Roo.HtmlEditorCore} this
42711 * Fires when the editor is first receives the focus. Any insertion must wait
42712 * until after this event.
42713 * @param {Roo.HtmlEditorCore} this
42717 * @event beforesync
42718 * Fires before the textarea is updated with content from the editor iframe. Return false
42719 * to cancel the sync.
42720 * @param {Roo.HtmlEditorCore} this
42721 * @param {String} html
42725 * @event beforepush
42726 * Fires before the iframe editor is updated with content from the textarea. Return false
42727 * to cancel the push.
42728 * @param {Roo.HtmlEditorCore} this
42729 * @param {String} html
42734 * Fires when the textarea is updated with content from the editor iframe.
42735 * @param {Roo.HtmlEditorCore} this
42736 * @param {String} html
42741 * Fires when the iframe editor is updated with content from the textarea.
42742 * @param {Roo.HtmlEditorCore} this
42743 * @param {String} html
42748 * @event editorevent
42749 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42750 * @param {Roo.HtmlEditorCore} this
42756 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42758 // defaults : white / black...
42759 this.applyBlacklists();
42766 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42770 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42776 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42781 * @cfg {Number} height (in pixels)
42785 * @cfg {Number} width (in pixels)
42790 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42793 stylesheets: false,
42798 // private properties
42799 validationEvent : false,
42801 initialized : false,
42803 sourceEditMode : false,
42804 onFocus : Roo.emptyFn,
42806 hideMode:'offsets',
42810 // blacklist + whitelisted elements..
42817 * Protected method that will not generally be called directly. It
42818 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42819 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42821 getDocMarkup : function(){
42825 // inherit styels from page...??
42826 if (this.stylesheets === false) {
42828 Roo.get(document.head).select('style').each(function(node) {
42829 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42832 Roo.get(document.head).select('link').each(function(node) {
42833 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42836 } else if (!this.stylesheets.length) {
42838 st = '<style type="text/css">' +
42839 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42845 st += '<style type="text/css">' +
42846 'IMG { cursor: pointer } ' +
42850 return '<html><head>' + st +
42851 //<style type="text/css">' +
42852 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42854 ' </head><body class="roo-htmleditor-body"></body></html>';
42858 onRender : function(ct, position)
42861 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42862 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42865 this.el.dom.style.border = '0 none';
42866 this.el.dom.setAttribute('tabIndex', -1);
42867 this.el.addClass('x-hidden hide');
42871 if(Roo.isIE){ // fix IE 1px bogus margin
42872 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42876 this.frameId = Roo.id();
42880 var iframe = this.owner.wrap.createChild({
42882 cls: 'form-control', // bootstrap..
42884 name: this.frameId,
42885 frameBorder : 'no',
42886 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42891 this.iframe = iframe.dom;
42893 this.assignDocWin();
42895 this.doc.designMode = 'on';
42898 this.doc.write(this.getDocMarkup());
42902 var task = { // must defer to wait for browser to be ready
42904 //console.log("run task?" + this.doc.readyState);
42905 this.assignDocWin();
42906 if(this.doc.body || this.doc.readyState == 'complete'){
42908 this.doc.designMode="on";
42912 Roo.TaskMgr.stop(task);
42913 this.initEditor.defer(10, this);
42920 Roo.TaskMgr.start(task);
42925 onResize : function(w, h)
42927 Roo.log('resize: ' +w + ',' + h );
42928 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42932 if(typeof w == 'number'){
42934 this.iframe.style.width = w + 'px';
42936 if(typeof h == 'number'){
42938 this.iframe.style.height = h + 'px';
42940 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42947 * Toggles the editor between standard and source edit mode.
42948 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42950 toggleSourceEdit : function(sourceEditMode){
42952 this.sourceEditMode = sourceEditMode === true;
42954 if(this.sourceEditMode){
42956 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42959 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42960 //this.iframe.className = '';
42963 //this.setSize(this.owner.wrap.getSize());
42964 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42971 * Protected method that will not generally be called directly. If you need/want
42972 * custom HTML cleanup, this is the method you should override.
42973 * @param {String} html The HTML to be cleaned
42974 * return {String} The cleaned HTML
42976 cleanHtml : function(html){
42977 html = String(html);
42978 if(html.length > 5){
42979 if(Roo.isSafari){ // strip safari nonsense
42980 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42983 if(html == ' '){
42990 * HTML Editor -> Textarea
42991 * Protected method that will not generally be called directly. Syncs the contents
42992 * of the editor iframe with the textarea.
42994 syncValue : function(){
42995 if(this.initialized){
42996 var bd = (this.doc.body || this.doc.documentElement);
42997 //this.cleanUpPaste(); -- this is done else where and causes havoc..
42998 var html = bd.innerHTML;
43000 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43001 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43003 html = '<div style="'+m[0]+'">' + html + '</div>';
43006 html = this.cleanHtml(html);
43007 // fix up the special chars.. normaly like back quotes in word...
43008 // however we do not want to do this with chinese..
43009 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43010 var cc = b.charCodeAt();
43012 (cc >= 0x4E00 && cc < 0xA000 ) ||
43013 (cc >= 0x3400 && cc < 0x4E00 ) ||
43014 (cc >= 0xf900 && cc < 0xfb00 )
43020 if(this.owner.fireEvent('beforesync', this, html) !== false){
43021 this.el.dom.value = html;
43022 this.owner.fireEvent('sync', this, html);
43028 * Protected method that will not generally be called directly. Pushes the value of the textarea
43029 * into the iframe editor.
43031 pushValue : function(){
43032 if(this.initialized){
43033 var v = this.el.dom.value.trim();
43035 // if(v.length < 1){
43039 if(this.owner.fireEvent('beforepush', this, v) !== false){
43040 var d = (this.doc.body || this.doc.documentElement);
43042 this.cleanUpPaste();
43043 this.el.dom.value = d.innerHTML;
43044 this.owner.fireEvent('push', this, v);
43050 deferFocus : function(){
43051 this.focus.defer(10, this);
43055 focus : function(){
43056 if(this.win && !this.sourceEditMode){
43063 assignDocWin: function()
43065 var iframe = this.iframe;
43068 this.doc = iframe.contentWindow.document;
43069 this.win = iframe.contentWindow;
43071 // if (!Roo.get(this.frameId)) {
43074 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43075 // this.win = Roo.get(this.frameId).dom.contentWindow;
43077 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43081 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43082 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43087 initEditor : function(){
43088 //console.log("INIT EDITOR");
43089 this.assignDocWin();
43093 this.doc.designMode="on";
43095 this.doc.write(this.getDocMarkup());
43098 var dbody = (this.doc.body || this.doc.documentElement);
43099 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43100 // this copies styles from the containing element into thsi one..
43101 // not sure why we need all of this..
43102 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43104 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43105 //ss['background-attachment'] = 'fixed'; // w3c
43106 dbody.bgProperties = 'fixed'; // ie
43107 //Roo.DomHelper.applyStyles(dbody, ss);
43108 Roo.EventManager.on(this.doc, {
43109 //'mousedown': this.onEditorEvent,
43110 'mouseup': this.onEditorEvent,
43111 'dblclick': this.onEditorEvent,
43112 'click': this.onEditorEvent,
43113 'keyup': this.onEditorEvent,
43118 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43120 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43121 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43123 this.initialized = true;
43125 this.owner.fireEvent('initialize', this);
43130 onDestroy : function(){
43136 //for (var i =0; i < this.toolbars.length;i++) {
43137 // // fixme - ask toolbars for heights?
43138 // this.toolbars[i].onDestroy();
43141 //this.wrap.dom.innerHTML = '';
43142 //this.wrap.remove();
43147 onFirstFocus : function(){
43149 this.assignDocWin();
43152 this.activated = true;
43155 if(Roo.isGecko){ // prevent silly gecko errors
43157 var s = this.win.getSelection();
43158 if(!s.focusNode || s.focusNode.nodeType != 3){
43159 var r = s.getRangeAt(0);
43160 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43165 this.execCmd('useCSS', true);
43166 this.execCmd('styleWithCSS', false);
43169 this.owner.fireEvent('activate', this);
43173 adjustFont: function(btn){
43174 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43175 //if(Roo.isSafari){ // safari
43178 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43179 if(Roo.isSafari){ // safari
43180 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43181 v = (v < 10) ? 10 : v;
43182 v = (v > 48) ? 48 : v;
43183 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43188 v = Math.max(1, v+adjust);
43190 this.execCmd('FontSize', v );
43193 onEditorEvent : function(e)
43195 this.owner.fireEvent('editorevent', this, e);
43196 // this.updateToolbar();
43197 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43200 insertTag : function(tg)
43202 // could be a bit smarter... -> wrap the current selected tRoo..
43203 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43205 range = this.createRange(this.getSelection());
43206 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43207 wrappingNode.appendChild(range.extractContents());
43208 range.insertNode(wrappingNode);
43215 this.execCmd("formatblock", tg);
43219 insertText : function(txt)
43223 var range = this.createRange();
43224 range.deleteContents();
43225 //alert(Sender.getAttribute('label'));
43227 range.insertNode(this.doc.createTextNode(txt));
43233 * Executes a Midas editor command on the editor document and performs necessary focus and
43234 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43235 * @param {String} cmd The Midas command
43236 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43238 relayCmd : function(cmd, value){
43240 this.execCmd(cmd, value);
43241 this.owner.fireEvent('editorevent', this);
43242 //this.updateToolbar();
43243 this.owner.deferFocus();
43247 * Executes a Midas editor command directly on the editor document.
43248 * For visual commands, you should use {@link #relayCmd} instead.
43249 * <b>This should only be called after the editor is initialized.</b>
43250 * @param {String} cmd The Midas command
43251 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43253 execCmd : function(cmd, value){
43254 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43261 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43263 * @param {String} text | dom node..
43265 insertAtCursor : function(text)
43268 if(!this.activated){
43274 var r = this.doc.selection.createRange();
43285 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43289 // from jquery ui (MIT licenced)
43291 var win = this.win;
43293 if (win.getSelection && win.getSelection().getRangeAt) {
43294 range = win.getSelection().getRangeAt(0);
43295 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43296 range.insertNode(node);
43297 } else if (win.document.selection && win.document.selection.createRange) {
43298 // no firefox support
43299 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43300 win.document.selection.createRange().pasteHTML(txt);
43302 // no firefox support
43303 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43304 this.execCmd('InsertHTML', txt);
43313 mozKeyPress : function(e){
43315 var c = e.getCharCode(), cmd;
43318 c = String.fromCharCode(c).toLowerCase();
43332 this.cleanUpPaste.defer(100, this);
43340 e.preventDefault();
43348 fixKeys : function(){ // load time branching for fastest keydown performance
43350 return function(e){
43351 var k = e.getKey(), r;
43354 r = this.doc.selection.createRange();
43357 r.pasteHTML('    ');
43364 r = this.doc.selection.createRange();
43366 var target = r.parentElement();
43367 if(!target || target.tagName.toLowerCase() != 'li'){
43369 r.pasteHTML('<br />');
43375 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43376 this.cleanUpPaste.defer(100, this);
43382 }else if(Roo.isOpera){
43383 return function(e){
43384 var k = e.getKey();
43388 this.execCmd('InsertHTML','    ');
43391 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43392 this.cleanUpPaste.defer(100, this);
43397 }else if(Roo.isSafari){
43398 return function(e){
43399 var k = e.getKey();
43403 this.execCmd('InsertText','\t');
43407 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43408 this.cleanUpPaste.defer(100, this);
43416 getAllAncestors: function()
43418 var p = this.getSelectedNode();
43421 a.push(p); // push blank onto stack..
43422 p = this.getParentElement();
43426 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43430 a.push(this.doc.body);
43434 lastSelNode : false,
43437 getSelection : function()
43439 this.assignDocWin();
43440 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43443 getSelectedNode: function()
43445 // this may only work on Gecko!!!
43447 // should we cache this!!!!
43452 var range = this.createRange(this.getSelection()).cloneRange();
43455 var parent = range.parentElement();
43457 var testRange = range.duplicate();
43458 testRange.moveToElementText(parent);
43459 if (testRange.inRange(range)) {
43462 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43465 parent = parent.parentElement;
43470 // is ancestor a text element.
43471 var ac = range.commonAncestorContainer;
43472 if (ac.nodeType == 3) {
43473 ac = ac.parentNode;
43476 var ar = ac.childNodes;
43479 var other_nodes = [];
43480 var has_other_nodes = false;
43481 for (var i=0;i<ar.length;i++) {
43482 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43485 // fullly contained node.
43487 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43492 // probably selected..
43493 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43494 other_nodes.push(ar[i]);
43498 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43503 has_other_nodes = true;
43505 if (!nodes.length && other_nodes.length) {
43506 nodes= other_nodes;
43508 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43514 createRange: function(sel)
43516 // this has strange effects when using with
43517 // top toolbar - not sure if it's a great idea.
43518 //this.editor.contentWindow.focus();
43519 if (typeof sel != "undefined") {
43521 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43523 return this.doc.createRange();
43526 return this.doc.createRange();
43529 getParentElement: function()
43532 this.assignDocWin();
43533 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43535 var range = this.createRange(sel);
43538 var p = range.commonAncestorContainer;
43539 while (p.nodeType == 3) { // text node
43550 * Range intersection.. the hard stuff...
43554 * [ -- selected range --- ]
43558 * if end is before start or hits it. fail.
43559 * if start is after end or hits it fail.
43561 * if either hits (but other is outside. - then it's not
43567 // @see http://www.thismuchiknow.co.uk/?p=64.
43568 rangeIntersectsNode : function(range, node)
43570 var nodeRange = node.ownerDocument.createRange();
43572 nodeRange.selectNode(node);
43574 nodeRange.selectNodeContents(node);
43577 var rangeStartRange = range.cloneRange();
43578 rangeStartRange.collapse(true);
43580 var rangeEndRange = range.cloneRange();
43581 rangeEndRange.collapse(false);
43583 var nodeStartRange = nodeRange.cloneRange();
43584 nodeStartRange.collapse(true);
43586 var nodeEndRange = nodeRange.cloneRange();
43587 nodeEndRange.collapse(false);
43589 return rangeStartRange.compareBoundaryPoints(
43590 Range.START_TO_START, nodeEndRange) == -1 &&
43591 rangeEndRange.compareBoundaryPoints(
43592 Range.START_TO_START, nodeStartRange) == 1;
43596 rangeCompareNode : function(range, node)
43598 var nodeRange = node.ownerDocument.createRange();
43600 nodeRange.selectNode(node);
43602 nodeRange.selectNodeContents(node);
43606 range.collapse(true);
43608 nodeRange.collapse(true);
43610 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43611 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43613 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43615 var nodeIsBefore = ss == 1;
43616 var nodeIsAfter = ee == -1;
43618 if (nodeIsBefore && nodeIsAfter) {
43621 if (!nodeIsBefore && nodeIsAfter) {
43622 return 1; //right trailed.
43625 if (nodeIsBefore && !nodeIsAfter) {
43626 return 2; // left trailed.
43632 // private? - in a new class?
43633 cleanUpPaste : function()
43635 // cleans up the whole document..
43636 Roo.log('cleanuppaste');
43638 this.cleanUpChildren(this.doc.body);
43639 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43640 if (clean != this.doc.body.innerHTML) {
43641 this.doc.body.innerHTML = clean;
43646 cleanWordChars : function(input) {// change the chars to hex code
43647 var he = Roo.HtmlEditorCore;
43649 var output = input;
43650 Roo.each(he.swapCodes, function(sw) {
43651 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43653 output = output.replace(swapper, sw[1]);
43660 cleanUpChildren : function (n)
43662 if (!n.childNodes.length) {
43665 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43666 this.cleanUpChild(n.childNodes[i]);
43673 cleanUpChild : function (node)
43676 //console.log(node);
43677 if (node.nodeName == "#text") {
43678 // clean up silly Windows -- stuff?
43681 if (node.nodeName == "#comment") {
43682 node.parentNode.removeChild(node);
43683 // clean up silly Windows -- stuff?
43686 var lcname = node.tagName.toLowerCase();
43687 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43688 // whitelist of tags..
43690 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43692 node.parentNode.removeChild(node);
43697 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43699 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43700 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43702 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43703 // remove_keep_children = true;
43706 if (remove_keep_children) {
43707 this.cleanUpChildren(node);
43708 // inserts everything just before this node...
43709 while (node.childNodes.length) {
43710 var cn = node.childNodes[0];
43711 node.removeChild(cn);
43712 node.parentNode.insertBefore(cn, node);
43714 node.parentNode.removeChild(node);
43718 if (!node.attributes || !node.attributes.length) {
43719 this.cleanUpChildren(node);
43723 function cleanAttr(n,v)
43726 if (v.match(/^\./) || v.match(/^\//)) {
43729 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43732 if (v.match(/^#/)) {
43735 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43736 node.removeAttribute(n);
43740 var cwhite = this.cwhite;
43741 var cblack = this.cblack;
43743 function cleanStyle(n,v)
43745 if (v.match(/expression/)) { //XSS?? should we even bother..
43746 node.removeAttribute(n);
43750 var parts = v.split(/;/);
43753 Roo.each(parts, function(p) {
43754 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43758 var l = p.split(':').shift().replace(/\s+/g,'');
43759 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43761 if ( cwhite.length && cblack.indexOf(l) > -1) {
43762 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43763 //node.removeAttribute(n);
43767 // only allow 'c whitelisted system attributes'
43768 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43769 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43770 //node.removeAttribute(n);
43780 if (clean.length) {
43781 node.setAttribute(n, clean.join(';'));
43783 node.removeAttribute(n);
43789 for (var i = node.attributes.length-1; i > -1 ; i--) {
43790 var a = node.attributes[i];
43793 if (a.name.toLowerCase().substr(0,2)=='on') {
43794 node.removeAttribute(a.name);
43797 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43798 node.removeAttribute(a.name);
43801 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43802 cleanAttr(a.name,a.value); // fixme..
43805 if (a.name == 'style') {
43806 cleanStyle(a.name,a.value);
43809 /// clean up MS crap..
43810 // tecnically this should be a list of valid class'es..
43813 if (a.name == 'class') {
43814 if (a.value.match(/^Mso/)) {
43815 node.className = '';
43818 if (a.value.match(/^body$/)) {
43819 node.className = '';
43830 this.cleanUpChildren(node);
43836 * Clean up MS wordisms...
43838 cleanWord : function(node)
43843 this.cleanWord(this.doc.body);
43846 if (node.nodeName == "#text") {
43847 // clean up silly Windows -- stuff?
43850 if (node.nodeName == "#comment") {
43851 node.parentNode.removeChild(node);
43852 // clean up silly Windows -- stuff?
43856 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43857 node.parentNode.removeChild(node);
43861 // remove - but keep children..
43862 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43863 while (node.childNodes.length) {
43864 var cn = node.childNodes[0];
43865 node.removeChild(cn);
43866 node.parentNode.insertBefore(cn, node);
43868 node.parentNode.removeChild(node);
43869 this.iterateChildren(node, this.cleanWord);
43873 if (node.className.length) {
43875 var cn = node.className.split(/\W+/);
43877 Roo.each(cn, function(cls) {
43878 if (cls.match(/Mso[a-zA-Z]+/)) {
43883 node.className = cna.length ? cna.join(' ') : '';
43885 node.removeAttribute("class");
43889 if (node.hasAttribute("lang")) {
43890 node.removeAttribute("lang");
43893 if (node.hasAttribute("style")) {
43895 var styles = node.getAttribute("style").split(";");
43897 Roo.each(styles, function(s) {
43898 if (!s.match(/:/)) {
43901 var kv = s.split(":");
43902 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43905 // what ever is left... we allow.
43908 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43909 if (!nstyle.length) {
43910 node.removeAttribute('style');
43913 this.iterateChildren(node, this.cleanWord);
43919 * iterateChildren of a Node, calling fn each time, using this as the scole..
43920 * @param {DomNode} node node to iterate children of.
43921 * @param {Function} fn method of this class to call on each item.
43923 iterateChildren : function(node, fn)
43925 if (!node.childNodes.length) {
43928 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43929 fn.call(this, node.childNodes[i])
43935 * cleanTableWidths.
43937 * Quite often pasting from word etc.. results in tables with column and widths.
43938 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43941 cleanTableWidths : function(node)
43946 this.cleanTableWidths(this.doc.body);
43951 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43954 Roo.log(node.tagName);
43955 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43956 this.iterateChildren(node, this.cleanTableWidths);
43959 if (node.hasAttribute('width')) {
43960 node.removeAttribute('width');
43964 if (node.hasAttribute("style")) {
43967 var styles = node.getAttribute("style").split(";");
43969 Roo.each(styles, function(s) {
43970 if (!s.match(/:/)) {
43973 var kv = s.split(":");
43974 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43977 // what ever is left... we allow.
43980 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43981 if (!nstyle.length) {
43982 node.removeAttribute('style');
43986 this.iterateChildren(node, this.cleanTableWidths);
43994 domToHTML : function(currentElement, depth, nopadtext) {
43996 depth = depth || 0;
43997 nopadtext = nopadtext || false;
43999 if (!currentElement) {
44000 return this.domToHTML(this.doc.body);
44003 //Roo.log(currentElement);
44005 var allText = false;
44006 var nodeName = currentElement.nodeName;
44007 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44009 if (nodeName == '#text') {
44011 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44016 if (nodeName != 'BODY') {
44019 // Prints the node tagName, such as <A>, <IMG>, etc
44022 for(i = 0; i < currentElement.attributes.length;i++) {
44024 var aname = currentElement.attributes.item(i).name;
44025 if (!currentElement.attributes.item(i).value.length) {
44028 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44031 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44040 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44043 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44048 // Traverse the tree
44050 var currentElementChild = currentElement.childNodes.item(i);
44051 var allText = true;
44052 var innerHTML = '';
44054 while (currentElementChild) {
44055 // Formatting code (indent the tree so it looks nice on the screen)
44056 var nopad = nopadtext;
44057 if (lastnode == 'SPAN') {
44061 if (currentElementChild.nodeName == '#text') {
44062 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44063 toadd = nopadtext ? toadd : toadd.trim();
44064 if (!nopad && toadd.length > 80) {
44065 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44067 innerHTML += toadd;
44070 currentElementChild = currentElement.childNodes.item(i);
44076 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44078 // Recursively traverse the tree structure of the child node
44079 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44080 lastnode = currentElementChild.nodeName;
44082 currentElementChild=currentElement.childNodes.item(i);
44088 // The remaining code is mostly for formatting the tree
44089 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44094 ret+= "</"+tagName+">";
44100 applyBlacklists : function()
44102 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44103 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44107 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44108 if (b.indexOf(tag) > -1) {
44111 this.white.push(tag);
44115 Roo.each(w, function(tag) {
44116 if (b.indexOf(tag) > -1) {
44119 if (this.white.indexOf(tag) > -1) {
44122 this.white.push(tag);
44127 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44128 if (w.indexOf(tag) > -1) {
44131 this.black.push(tag);
44135 Roo.each(b, function(tag) {
44136 if (w.indexOf(tag) > -1) {
44139 if (this.black.indexOf(tag) > -1) {
44142 this.black.push(tag);
44147 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44148 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44152 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44153 if (b.indexOf(tag) > -1) {
44156 this.cwhite.push(tag);
44160 Roo.each(w, function(tag) {
44161 if (b.indexOf(tag) > -1) {
44164 if (this.cwhite.indexOf(tag) > -1) {
44167 this.cwhite.push(tag);
44172 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44173 if (w.indexOf(tag) > -1) {
44176 this.cblack.push(tag);
44180 Roo.each(b, function(tag) {
44181 if (w.indexOf(tag) > -1) {
44184 if (this.cblack.indexOf(tag) > -1) {
44187 this.cblack.push(tag);
44192 setStylesheets : function(stylesheets)
44194 if(typeof(stylesheets) == 'string'){
44195 Roo.get(this.iframe.contentDocument.head).createChild({
44197 rel : 'stylesheet',
44206 Roo.each(stylesheets, function(s) {
44211 Roo.get(_this.iframe.contentDocument.head).createChild({
44213 rel : 'stylesheet',
44222 removeStylesheets : function()
44226 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44231 // hide stuff that is not compatible
44245 * @event specialkey
44249 * @cfg {String} fieldClass @hide
44252 * @cfg {String} focusClass @hide
44255 * @cfg {String} autoCreate @hide
44258 * @cfg {String} inputType @hide
44261 * @cfg {String} invalidClass @hide
44264 * @cfg {String} invalidText @hide
44267 * @cfg {String} msgFx @hide
44270 * @cfg {String} validateOnBlur @hide
44274 Roo.HtmlEditorCore.white = [
44275 'area', 'br', 'img', 'input', 'hr', 'wbr',
44277 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44278 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44279 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44280 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44281 'table', 'ul', 'xmp',
44283 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44286 'dir', 'menu', 'ol', 'ul', 'dl',
44292 Roo.HtmlEditorCore.black = [
44293 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44295 'base', 'basefont', 'bgsound', 'blink', 'body',
44296 'frame', 'frameset', 'head', 'html', 'ilayer',
44297 'iframe', 'layer', 'link', 'meta', 'object',
44298 'script', 'style' ,'title', 'xml' // clean later..
44300 Roo.HtmlEditorCore.clean = [
44301 'script', 'style', 'title', 'xml'
44303 Roo.HtmlEditorCore.remove = [
44308 Roo.HtmlEditorCore.ablack = [
44312 Roo.HtmlEditorCore.aclean = [
44313 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44317 Roo.HtmlEditorCore.pwhite= [
44318 'http', 'https', 'mailto'
44321 // white listed style attributes.
44322 Roo.HtmlEditorCore.cwhite= [
44323 // 'text-align', /// default is to allow most things..
44329 // black listed style attributes.
44330 Roo.HtmlEditorCore.cblack= [
44331 // 'font-size' -- this can be set by the project
44335 Roo.HtmlEditorCore.swapCodes =[
44346 //<script type="text/javascript">
44349 * Ext JS Library 1.1.1
44350 * Copyright(c) 2006-2007, Ext JS, LLC.
44356 Roo.form.HtmlEditor = function(config){
44360 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44362 if (!this.toolbars) {
44363 this.toolbars = [];
44365 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44371 * @class Roo.form.HtmlEditor
44372 * @extends Roo.form.Field
44373 * Provides a lightweight HTML Editor component.
44375 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44377 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44378 * supported by this editor.</b><br/><br/>
44379 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44380 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44382 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44384 * @cfg {Boolean} clearUp
44388 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44393 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44398 * @cfg {Number} height (in pixels)
44402 * @cfg {Number} width (in pixels)
44407 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44410 stylesheets: false,
44414 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44419 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44425 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44430 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44438 // private properties
44439 validationEvent : false,
44441 initialized : false,
44444 onFocus : Roo.emptyFn,
44446 hideMode:'offsets',
44448 actionMode : 'container', // defaults to hiding it...
44450 defaultAutoCreate : { // modified by initCompnoent..
44452 style:"width:500px;height:300px;",
44453 autocomplete: "new-password"
44457 initComponent : function(){
44460 * @event initialize
44461 * Fires when the editor is fully initialized (including the iframe)
44462 * @param {HtmlEditor} this
44467 * Fires when the editor is first receives the focus. Any insertion must wait
44468 * until after this event.
44469 * @param {HtmlEditor} this
44473 * @event beforesync
44474 * Fires before the textarea is updated with content from the editor iframe. Return false
44475 * to cancel the sync.
44476 * @param {HtmlEditor} this
44477 * @param {String} html
44481 * @event beforepush
44482 * Fires before the iframe editor is updated with content from the textarea. Return false
44483 * to cancel the push.
44484 * @param {HtmlEditor} this
44485 * @param {String} html
44490 * Fires when the textarea is updated with content from the editor iframe.
44491 * @param {HtmlEditor} this
44492 * @param {String} html
44497 * Fires when the iframe editor is updated with content from the textarea.
44498 * @param {HtmlEditor} this
44499 * @param {String} html
44503 * @event editmodechange
44504 * Fires when the editor switches edit modes
44505 * @param {HtmlEditor} this
44506 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44508 editmodechange: true,
44510 * @event editorevent
44511 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44512 * @param {HtmlEditor} this
44516 * @event firstfocus
44517 * Fires when on first focus - needed by toolbars..
44518 * @param {HtmlEditor} this
44523 * Auto save the htmlEditor value as a file into Events
44524 * @param {HtmlEditor} this
44528 * @event savedpreview
44529 * preview the saved version of htmlEditor
44530 * @param {HtmlEditor} this
44532 savedpreview: true,
44535 * @event stylesheetsclick
44536 * Fires when press the Sytlesheets button
44537 * @param {Roo.HtmlEditorCore} this
44539 stylesheetsclick: true
44541 this.defaultAutoCreate = {
44543 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44544 autocomplete: "new-password"
44549 * Protected method that will not generally be called directly. It
44550 * is called when the editor creates its toolbar. Override this method if you need to
44551 * add custom toolbar buttons.
44552 * @param {HtmlEditor} editor
44554 createToolbar : function(editor){
44555 Roo.log("create toolbars");
44556 if (!editor.toolbars || !editor.toolbars.length) {
44557 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44560 for (var i =0 ; i < editor.toolbars.length;i++) {
44561 editor.toolbars[i] = Roo.factory(
44562 typeof(editor.toolbars[i]) == 'string' ?
44563 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44564 Roo.form.HtmlEditor);
44565 editor.toolbars[i].init(editor);
44573 onRender : function(ct, position)
44576 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44578 this.wrap = this.el.wrap({
44579 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44582 this.editorcore.onRender(ct, position);
44584 if (this.resizable) {
44585 this.resizeEl = new Roo.Resizable(this.wrap, {
44589 minHeight : this.height,
44590 height: this.height,
44591 handles : this.resizable,
44594 resize : function(r, w, h) {
44595 _t.onResize(w,h); // -something
44601 this.createToolbar(this);
44605 this.setSize(this.wrap.getSize());
44607 if (this.resizeEl) {
44608 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44609 // should trigger onReize..
44612 this.keyNav = new Roo.KeyNav(this.el, {
44614 "tab" : function(e){
44615 e.preventDefault();
44617 var value = this.getValue();
44619 var start = this.el.dom.selectionStart;
44620 var end = this.el.dom.selectionEnd;
44624 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44625 this.el.dom.setSelectionRange(end + 1, end + 1);
44629 var f = value.substring(0, start).split("\t");
44631 if(f.pop().length != 0){
44635 this.setValue(f.join("\t") + value.substring(end));
44636 this.el.dom.setSelectionRange(start - 1, start - 1);
44640 "home" : function(e){
44641 e.preventDefault();
44643 var curr = this.el.dom.selectionStart;
44644 var lines = this.getValue().split("\n");
44651 this.el.dom.setSelectionRange(0, 0);
44657 for (var i = 0; i < lines.length;i++) {
44658 pos += lines[i].length;
44668 pos -= lines[i].length;
44674 this.el.dom.setSelectionRange(pos, pos);
44678 this.el.dom.selectionStart = pos;
44679 this.el.dom.selectionEnd = curr;
44682 "end" : function(e){
44683 e.preventDefault();
44685 var curr = this.el.dom.selectionStart;
44686 var lines = this.getValue().split("\n");
44693 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44699 for (var i = 0; i < lines.length;i++) {
44701 pos += lines[i].length;
44715 this.el.dom.setSelectionRange(pos, pos);
44719 this.el.dom.selectionStart = curr;
44720 this.el.dom.selectionEnd = pos;
44725 doRelay : function(foo, bar, hname){
44726 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44732 // if(this.autosave && this.w){
44733 // this.autoSaveFn = setInterval(this.autosave, 1000);
44738 onResize : function(w, h)
44740 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44745 if(typeof w == 'number'){
44746 var aw = w - this.wrap.getFrameWidth('lr');
44747 this.el.setWidth(this.adjustWidth('textarea', aw));
44750 if(typeof h == 'number'){
44752 for (var i =0; i < this.toolbars.length;i++) {
44753 // fixme - ask toolbars for heights?
44754 tbh += this.toolbars[i].tb.el.getHeight();
44755 if (this.toolbars[i].footer) {
44756 tbh += this.toolbars[i].footer.el.getHeight();
44763 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44764 ah -= 5; // knock a few pixes off for look..
44766 this.el.setHeight(this.adjustWidth('textarea', ah));
44770 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44771 this.editorcore.onResize(ew,eh);
44776 * Toggles the editor between standard and source edit mode.
44777 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44779 toggleSourceEdit : function(sourceEditMode)
44781 this.editorcore.toggleSourceEdit(sourceEditMode);
44783 if(this.editorcore.sourceEditMode){
44784 Roo.log('editor - showing textarea');
44787 // Roo.log(this.syncValue());
44788 this.editorcore.syncValue();
44789 this.el.removeClass('x-hidden');
44790 this.el.dom.removeAttribute('tabIndex');
44793 for (var i = 0; i < this.toolbars.length; i++) {
44794 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44795 this.toolbars[i].tb.hide();
44796 this.toolbars[i].footer.hide();
44801 Roo.log('editor - hiding textarea');
44803 // Roo.log(this.pushValue());
44804 this.editorcore.pushValue();
44806 this.el.addClass('x-hidden');
44807 this.el.dom.setAttribute('tabIndex', -1);
44809 for (var i = 0; i < this.toolbars.length; i++) {
44810 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44811 this.toolbars[i].tb.show();
44812 this.toolbars[i].footer.show();
44816 //this.deferFocus();
44819 this.setSize(this.wrap.getSize());
44820 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44822 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44825 // private (for BoxComponent)
44826 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44828 // private (for BoxComponent)
44829 getResizeEl : function(){
44833 // private (for BoxComponent)
44834 getPositionEl : function(){
44839 initEvents : function(){
44840 this.originalValue = this.getValue();
44844 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44847 markInvalid : Roo.emptyFn,
44849 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44852 clearInvalid : Roo.emptyFn,
44854 setValue : function(v){
44855 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44856 this.editorcore.pushValue();
44861 deferFocus : function(){
44862 this.focus.defer(10, this);
44866 focus : function(){
44867 this.editorcore.focus();
44873 onDestroy : function(){
44879 for (var i =0; i < this.toolbars.length;i++) {
44880 // fixme - ask toolbars for heights?
44881 this.toolbars[i].onDestroy();
44884 this.wrap.dom.innerHTML = '';
44885 this.wrap.remove();
44890 onFirstFocus : function(){
44891 //Roo.log("onFirstFocus");
44892 this.editorcore.onFirstFocus();
44893 for (var i =0; i < this.toolbars.length;i++) {
44894 this.toolbars[i].onFirstFocus();
44900 syncValue : function()
44902 this.editorcore.syncValue();
44905 pushValue : function()
44907 this.editorcore.pushValue();
44910 setStylesheets : function(stylesheets)
44912 this.editorcore.setStylesheets(stylesheets);
44915 removeStylesheets : function()
44917 this.editorcore.removeStylesheets();
44921 // hide stuff that is not compatible
44935 * @event specialkey
44939 * @cfg {String} fieldClass @hide
44942 * @cfg {String} focusClass @hide
44945 * @cfg {String} autoCreate @hide
44948 * @cfg {String} inputType @hide
44951 * @cfg {String} invalidClass @hide
44954 * @cfg {String} invalidText @hide
44957 * @cfg {String} msgFx @hide
44960 * @cfg {String} validateOnBlur @hide
44964 // <script type="text/javascript">
44967 * Ext JS Library 1.1.1
44968 * Copyright(c) 2006-2007, Ext JS, LLC.
44974 * @class Roo.form.HtmlEditorToolbar1
44979 new Roo.form.HtmlEditor({
44982 new Roo.form.HtmlEditorToolbar1({
44983 disable : { fonts: 1 , format: 1, ..., ... , ...],
44989 * @cfg {Object} disable List of elements to disable..
44990 * @cfg {Array} btns List of additional buttons.
44994 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
44997 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45000 Roo.apply(this, config);
45002 // default disabled, based on 'good practice'..
45003 this.disable = this.disable || {};
45004 Roo.applyIf(this.disable, {
45007 specialElements : true
45011 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45012 // dont call parent... till later.
45015 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45022 editorcore : false,
45024 * @cfg {Object} disable List of toolbar elements to disable
45031 * @cfg {String} createLinkText The default text for the create link prompt
45033 createLinkText : 'Please enter the URL for the link:',
45035 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45037 defaultLinkValue : 'http:/'+'/',
45041 * @cfg {Array} fontFamilies An array of available font families
45059 // "á" , ?? a acute?
45064 "°" // , // degrees
45066 // "é" , // e ecute
45067 // "ú" , // u ecute?
45070 specialElements : [
45072 text: "Insert Table",
45075 ihtml : '<table><tr><td>Cell</td></tr></table>'
45079 text: "Insert Image",
45082 ihtml : '<img src="about:blank"/>'
45091 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45092 "input:submit", "input:button", "select", "textarea", "label" ],
45095 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45097 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45105 * @cfg {String} defaultFont default font to use.
45107 defaultFont: 'tahoma',
45109 fontSelect : false,
45112 formatCombo : false,
45114 init : function(editor)
45116 this.editor = editor;
45117 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45118 var editorcore = this.editorcore;
45122 var fid = editorcore.frameId;
45124 function btn(id, toggle, handler){
45125 var xid = fid + '-'+ id ;
45129 cls : 'x-btn-icon x-edit-'+id,
45130 enableToggle:toggle !== false,
45131 scope: _t, // was editor...
45132 handler:handler||_t.relayBtnCmd,
45133 clickEvent:'mousedown',
45134 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45141 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45143 // stop form submits
45144 tb.el.on('click', function(e){
45145 e.preventDefault(); // what does this do?
45148 if(!this.disable.font) { // && !Roo.isSafari){
45149 /* why no safari for fonts
45150 editor.fontSelect = tb.el.createChild({
45153 cls:'x-font-select',
45154 html: this.createFontOptions()
45157 editor.fontSelect.on('change', function(){
45158 var font = editor.fontSelect.dom.value;
45159 editor.relayCmd('fontname', font);
45160 editor.deferFocus();
45164 editor.fontSelect.dom,
45170 if(!this.disable.formats){
45171 this.formatCombo = new Roo.form.ComboBox({
45172 store: new Roo.data.SimpleStore({
45175 data : this.formats // from states.js
45179 //autoCreate : {tag: "div", size: "20"},
45180 displayField:'tag',
45184 triggerAction: 'all',
45185 emptyText:'Add tag',
45186 selectOnFocus:true,
45189 'select': function(c, r, i) {
45190 editorcore.insertTag(r.get('tag'));
45196 tb.addField(this.formatCombo);
45200 if(!this.disable.format){
45205 btn('strikethrough')
45208 if(!this.disable.fontSize){
45213 btn('increasefontsize', false, editorcore.adjustFont),
45214 btn('decreasefontsize', false, editorcore.adjustFont)
45219 if(!this.disable.colors){
45222 id:editorcore.frameId +'-forecolor',
45223 cls:'x-btn-icon x-edit-forecolor',
45224 clickEvent:'mousedown',
45225 tooltip: this.buttonTips['forecolor'] || undefined,
45227 menu : new Roo.menu.ColorMenu({
45228 allowReselect: true,
45229 focus: Roo.emptyFn,
45232 selectHandler: function(cp, color){
45233 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45234 editor.deferFocus();
45237 clickEvent:'mousedown'
45240 id:editorcore.frameId +'backcolor',
45241 cls:'x-btn-icon x-edit-backcolor',
45242 clickEvent:'mousedown',
45243 tooltip: this.buttonTips['backcolor'] || undefined,
45245 menu : new Roo.menu.ColorMenu({
45246 focus: Roo.emptyFn,
45249 allowReselect: true,
45250 selectHandler: function(cp, color){
45252 editorcore.execCmd('useCSS', false);
45253 editorcore.execCmd('hilitecolor', color);
45254 editorcore.execCmd('useCSS', true);
45255 editor.deferFocus();
45257 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45258 Roo.isSafari || Roo.isIE ? '#'+color : color);
45259 editor.deferFocus();
45263 clickEvent:'mousedown'
45268 // now add all the items...
45271 if(!this.disable.alignments){
45274 btn('justifyleft'),
45275 btn('justifycenter'),
45276 btn('justifyright')
45280 //if(!Roo.isSafari){
45281 if(!this.disable.links){
45284 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45288 if(!this.disable.lists){
45291 btn('insertorderedlist'),
45292 btn('insertunorderedlist')
45295 if(!this.disable.sourceEdit){
45298 btn('sourceedit', true, function(btn){
45299 this.toggleSourceEdit(btn.pressed);
45306 // special menu.. - needs to be tidied up..
45307 if (!this.disable.special) {
45310 cls: 'x-edit-none',
45316 for (var i =0; i < this.specialChars.length; i++) {
45317 smenu.menu.items.push({
45319 html: this.specialChars[i],
45320 handler: function(a,b) {
45321 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45322 //editor.insertAtCursor(a.html);
45336 if (!this.disable.cleanStyles) {
45338 cls: 'x-btn-icon x-btn-clear',
45344 for (var i =0; i < this.cleanStyles.length; i++) {
45345 cmenu.menu.items.push({
45346 actiontype : this.cleanStyles[i],
45347 html: 'Remove ' + this.cleanStyles[i],
45348 handler: function(a,b) {
45351 var c = Roo.get(editorcore.doc.body);
45352 c.select('[style]').each(function(s) {
45353 s.dom.style.removeProperty(a.actiontype);
45355 editorcore.syncValue();
45360 cmenu.menu.items.push({
45361 actiontype : 'tablewidths',
45362 html: 'Remove Table Widths',
45363 handler: function(a,b) {
45364 editorcore.cleanTableWidths();
45365 editorcore.syncValue();
45369 cmenu.menu.items.push({
45370 actiontype : 'word',
45371 html: 'Remove MS Word Formating',
45372 handler: function(a,b) {
45373 editorcore.cleanWord();
45374 editorcore.syncValue();
45379 cmenu.menu.items.push({
45380 actiontype : 'all',
45381 html: 'Remove All Styles',
45382 handler: function(a,b) {
45384 var c = Roo.get(editorcore.doc.body);
45385 c.select('[style]').each(function(s) {
45386 s.dom.removeAttribute('style');
45388 editorcore.syncValue();
45393 cmenu.menu.items.push({
45394 actiontype : 'all',
45395 html: 'Remove All CSS Classes',
45396 handler: function(a,b) {
45398 var c = Roo.get(editorcore.doc.body);
45399 c.select('[class]').each(function(s) {
45400 s.dom.className = '';
45402 editorcore.syncValue();
45407 cmenu.menu.items.push({
45408 actiontype : 'tidy',
45409 html: 'Tidy HTML Source',
45410 handler: function(a,b) {
45411 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45412 editorcore.syncValue();
45421 if (!this.disable.specialElements) {
45424 cls: 'x-edit-none',
45429 for (var i =0; i < this.specialElements.length; i++) {
45430 semenu.menu.items.push(
45432 handler: function(a,b) {
45433 editor.insertAtCursor(this.ihtml);
45435 }, this.specialElements[i])
45447 for(var i =0; i< this.btns.length;i++) {
45448 var b = Roo.factory(this.btns[i],Roo.form);
45449 b.cls = 'x-edit-none';
45451 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45452 b.cls += ' x-init-enable';
45455 b.scope = editorcore;
45463 // disable everything...
45465 this.tb.items.each(function(item){
45468 item.id != editorcore.frameId+ '-sourceedit' &&
45469 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45475 this.rendered = true;
45477 // the all the btns;
45478 editor.on('editorevent', this.updateToolbar, this);
45479 // other toolbars need to implement this..
45480 //editor.on('editmodechange', this.updateToolbar, this);
45484 relayBtnCmd : function(btn) {
45485 this.editorcore.relayCmd(btn.cmd);
45487 // private used internally
45488 createLink : function(){
45489 Roo.log("create link?");
45490 var url = prompt(this.createLinkText, this.defaultLinkValue);
45491 if(url && url != 'http:/'+'/'){
45492 this.editorcore.relayCmd('createlink', url);
45498 * Protected method that will not generally be called directly. It triggers
45499 * a toolbar update by reading the markup state of the current selection in the editor.
45501 updateToolbar: function(){
45503 if(!this.editorcore.activated){
45504 this.editor.onFirstFocus();
45508 var btns = this.tb.items.map,
45509 doc = this.editorcore.doc,
45510 frameId = this.editorcore.frameId;
45512 if(!this.disable.font && !Roo.isSafari){
45514 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45515 if(name != this.fontSelect.dom.value){
45516 this.fontSelect.dom.value = name;
45520 if(!this.disable.format){
45521 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45522 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45523 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45524 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45526 if(!this.disable.alignments){
45527 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45528 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45529 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45531 if(!Roo.isSafari && !this.disable.lists){
45532 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45533 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45536 var ans = this.editorcore.getAllAncestors();
45537 if (this.formatCombo) {
45540 var store = this.formatCombo.store;
45541 this.formatCombo.setValue("");
45542 for (var i =0; i < ans.length;i++) {
45543 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45545 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45553 // hides menus... - so this cant be on a menu...
45554 Roo.menu.MenuMgr.hideAll();
45556 //this.editorsyncValue();
45560 createFontOptions : function(){
45561 var buf = [], fs = this.fontFamilies, ff, lc;
45565 for(var i = 0, len = fs.length; i< len; i++){
45567 lc = ff.toLowerCase();
45569 '<option value="',lc,'" style="font-family:',ff,';"',
45570 (this.defaultFont == lc ? ' selected="true">' : '>'),
45575 return buf.join('');
45578 toggleSourceEdit : function(sourceEditMode){
45580 Roo.log("toolbar toogle");
45581 if(sourceEditMode === undefined){
45582 sourceEditMode = !this.sourceEditMode;
45584 this.sourceEditMode = sourceEditMode === true;
45585 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45586 // just toggle the button?
45587 if(btn.pressed !== this.sourceEditMode){
45588 btn.toggle(this.sourceEditMode);
45592 if(sourceEditMode){
45593 Roo.log("disabling buttons");
45594 this.tb.items.each(function(item){
45595 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45601 Roo.log("enabling buttons");
45602 if(this.editorcore.initialized){
45603 this.tb.items.each(function(item){
45609 Roo.log("calling toggole on editor");
45610 // tell the editor that it's been pressed..
45611 this.editor.toggleSourceEdit(sourceEditMode);
45615 * Object collection of toolbar tooltips for the buttons in the editor. The key
45616 * is the command id associated with that button and the value is a valid QuickTips object.
45621 title: 'Bold (Ctrl+B)',
45622 text: 'Make the selected text bold.',
45623 cls: 'x-html-editor-tip'
45626 title: 'Italic (Ctrl+I)',
45627 text: 'Make the selected text italic.',
45628 cls: 'x-html-editor-tip'
45636 title: 'Bold (Ctrl+B)',
45637 text: 'Make the selected text bold.',
45638 cls: 'x-html-editor-tip'
45641 title: 'Italic (Ctrl+I)',
45642 text: 'Make the selected text italic.',
45643 cls: 'x-html-editor-tip'
45646 title: 'Underline (Ctrl+U)',
45647 text: 'Underline the selected text.',
45648 cls: 'x-html-editor-tip'
45651 title: 'Strikethrough',
45652 text: 'Strikethrough the selected text.',
45653 cls: 'x-html-editor-tip'
45655 increasefontsize : {
45656 title: 'Grow Text',
45657 text: 'Increase the font size.',
45658 cls: 'x-html-editor-tip'
45660 decreasefontsize : {
45661 title: 'Shrink Text',
45662 text: 'Decrease the font size.',
45663 cls: 'x-html-editor-tip'
45666 title: 'Text Highlight Color',
45667 text: 'Change the background color of the selected text.',
45668 cls: 'x-html-editor-tip'
45671 title: 'Font Color',
45672 text: 'Change the color of the selected text.',
45673 cls: 'x-html-editor-tip'
45676 title: 'Align Text Left',
45677 text: 'Align text to the left.',
45678 cls: 'x-html-editor-tip'
45681 title: 'Center Text',
45682 text: 'Center text in the editor.',
45683 cls: 'x-html-editor-tip'
45686 title: 'Align Text Right',
45687 text: 'Align text to the right.',
45688 cls: 'x-html-editor-tip'
45690 insertunorderedlist : {
45691 title: 'Bullet List',
45692 text: 'Start a bulleted list.',
45693 cls: 'x-html-editor-tip'
45695 insertorderedlist : {
45696 title: 'Numbered List',
45697 text: 'Start a numbered list.',
45698 cls: 'x-html-editor-tip'
45701 title: 'Hyperlink',
45702 text: 'Make the selected text a hyperlink.',
45703 cls: 'x-html-editor-tip'
45706 title: 'Source Edit',
45707 text: 'Switch to source editing mode.',
45708 cls: 'x-html-editor-tip'
45712 onDestroy : function(){
45715 this.tb.items.each(function(item){
45717 item.menu.removeAll();
45719 item.menu.el.destroy();
45727 onFirstFocus: function() {
45728 this.tb.items.each(function(item){
45737 // <script type="text/javascript">
45740 * Ext JS Library 1.1.1
45741 * Copyright(c) 2006-2007, Ext JS, LLC.
45748 * @class Roo.form.HtmlEditor.ToolbarContext
45753 new Roo.form.HtmlEditor({
45756 { xtype: 'ToolbarStandard', styles : {} }
45757 { xtype: 'ToolbarContext', disable : {} }
45763 * @config : {Object} disable List of elements to disable.. (not done yet.)
45764 * @config : {Object} styles Map of styles available.
45768 Roo.form.HtmlEditor.ToolbarContext = function(config)
45771 Roo.apply(this, config);
45772 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45773 // dont call parent... till later.
45774 this.styles = this.styles || {};
45779 Roo.form.HtmlEditor.ToolbarContext.types = {
45791 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45857 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45862 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45872 style : 'fontFamily',
45873 displayField: 'display',
45874 optname : 'font-family',
45923 // should we really allow this??
45924 // should this just be
45935 style : 'fontFamily',
45936 displayField: 'display',
45937 optname : 'font-family',
45944 style : 'fontFamily',
45945 displayField: 'display',
45946 optname : 'font-family',
45953 style : 'fontFamily',
45954 displayField: 'display',
45955 optname : 'font-family',
45966 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45967 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45969 Roo.form.HtmlEditor.ToolbarContext.options = {
45971 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45972 [ 'Courier New', 'Courier New'],
45973 [ 'Tahoma', 'Tahoma'],
45974 [ 'Times New Roman,serif', 'Times'],
45975 [ 'Verdana','Verdana' ]
45979 // fixme - these need to be configurable..
45982 //Roo.form.HtmlEditor.ToolbarContext.types
45985 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
45992 editorcore : false,
45994 * @cfg {Object} disable List of toolbar elements to disable
45999 * @cfg {Object} styles List of styles
46000 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46002 * These must be defined in the page, so they get rendered correctly..
46013 init : function(editor)
46015 this.editor = editor;
46016 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46017 var editorcore = this.editorcore;
46019 var fid = editorcore.frameId;
46021 function btn(id, toggle, handler){
46022 var xid = fid + '-'+ id ;
46026 cls : 'x-btn-icon x-edit-'+id,
46027 enableToggle:toggle !== false,
46028 scope: editorcore, // was editor...
46029 handler:handler||editorcore.relayBtnCmd,
46030 clickEvent:'mousedown',
46031 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46035 // create a new element.
46036 var wdiv = editor.wrap.createChild({
46038 }, editor.wrap.dom.firstChild.nextSibling, true);
46040 // can we do this more than once??
46042 // stop form submits
46045 // disable everything...
46046 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46047 this.toolbars = {};
46049 for (var i in ty) {
46051 this.toolbars[i] = this.buildToolbar(ty[i],i);
46053 this.tb = this.toolbars.BODY;
46055 this.buildFooter();
46056 this.footer.show();
46057 editor.on('hide', function( ) { this.footer.hide() }, this);
46058 editor.on('show', function( ) { this.footer.show() }, this);
46061 this.rendered = true;
46063 // the all the btns;
46064 editor.on('editorevent', this.updateToolbar, this);
46065 // other toolbars need to implement this..
46066 //editor.on('editmodechange', this.updateToolbar, this);
46072 * Protected method that will not generally be called directly. It triggers
46073 * a toolbar update by reading the markup state of the current selection in the editor.
46075 * Note you can force an update by calling on('editorevent', scope, false)
46077 updateToolbar: function(editor,ev,sel){
46080 // capture mouse up - this is handy for selecting images..
46081 // perhaps should go somewhere else...
46082 if(!this.editorcore.activated){
46083 this.editor.onFirstFocus();
46089 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46090 // selectNode - might want to handle IE?
46092 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46093 ev.target && ev.target.tagName == 'IMG') {
46094 // they have click on an image...
46095 // let's see if we can change the selection...
46098 var nodeRange = sel.ownerDocument.createRange();
46100 nodeRange.selectNode(sel);
46102 nodeRange.selectNodeContents(sel);
46104 //nodeRange.collapse(true);
46105 var s = this.editorcore.win.getSelection();
46106 s.removeAllRanges();
46107 s.addRange(nodeRange);
46111 var updateFooter = sel ? false : true;
46114 var ans = this.editorcore.getAllAncestors();
46117 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46120 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46121 sel = sel ? sel : this.editorcore.doc.body;
46122 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46125 // pick a menu that exists..
46126 var tn = sel.tagName.toUpperCase();
46127 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46129 tn = sel.tagName.toUpperCase();
46131 var lastSel = this.tb.selectedNode;
46133 this.tb.selectedNode = sel;
46135 // if current menu does not match..
46137 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46140 ///console.log("show: " + tn);
46141 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46144 this.tb.items.first().el.innerHTML = tn + ': ';
46147 // update attributes
46148 if (this.tb.fields) {
46149 this.tb.fields.each(function(e) {
46151 e.setValue(sel.style[e.stylename]);
46154 e.setValue(sel.getAttribute(e.attrname));
46158 var hasStyles = false;
46159 for(var i in this.styles) {
46166 var st = this.tb.fields.item(0);
46168 st.store.removeAll();
46171 var cn = sel.className.split(/\s+/);
46174 if (this.styles['*']) {
46176 Roo.each(this.styles['*'], function(v) {
46177 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46180 if (this.styles[tn]) {
46181 Roo.each(this.styles[tn], function(v) {
46182 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46186 st.store.loadData(avs);
46190 // flag our selected Node.
46191 this.tb.selectedNode = sel;
46194 Roo.menu.MenuMgr.hideAll();
46198 if (!updateFooter) {
46199 //this.footDisp.dom.innerHTML = '';
46202 // update the footer
46206 this.footerEls = ans.reverse();
46207 Roo.each(this.footerEls, function(a,i) {
46208 if (!a) { return; }
46209 html += html.length ? ' > ' : '';
46211 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46216 var sz = this.footDisp.up('td').getSize();
46217 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46218 this.footDisp.dom.style.marginLeft = '5px';
46220 this.footDisp.dom.style.overflow = 'hidden';
46222 this.footDisp.dom.innerHTML = html;
46224 //this.editorsyncValue();
46231 onDestroy : function(){
46234 this.tb.items.each(function(item){
46236 item.menu.removeAll();
46238 item.menu.el.destroy();
46246 onFirstFocus: function() {
46247 // need to do this for all the toolbars..
46248 this.tb.items.each(function(item){
46252 buildToolbar: function(tlist, nm)
46254 var editor = this.editor;
46255 var editorcore = this.editorcore;
46256 // create a new element.
46257 var wdiv = editor.wrap.createChild({
46259 }, editor.wrap.dom.firstChild.nextSibling, true);
46262 var tb = new Roo.Toolbar(wdiv);
46265 tb.add(nm+ ": ");
46268 for(var i in this.styles) {
46273 if (styles && styles.length) {
46275 // this needs a multi-select checkbox...
46276 tb.addField( new Roo.form.ComboBox({
46277 store: new Roo.data.SimpleStore({
46279 fields: ['val', 'selected'],
46282 name : '-roo-edit-className',
46283 attrname : 'className',
46284 displayField: 'val',
46288 triggerAction: 'all',
46289 emptyText:'Select Style',
46290 selectOnFocus:true,
46293 'select': function(c, r, i) {
46294 // initial support only for on class per el..
46295 tb.selectedNode.className = r ? r.get('val') : '';
46296 editorcore.syncValue();
46303 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46304 var tbops = tbc.options;
46306 for (var i in tlist) {
46308 var item = tlist[i];
46309 tb.add(item.title + ": ");
46312 //optname == used so you can configure the options available..
46313 var opts = item.opts ? item.opts : false;
46314 if (item.optname) {
46315 opts = tbops[item.optname];
46320 // opts == pulldown..
46321 tb.addField( new Roo.form.ComboBox({
46322 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46324 fields: ['val', 'display'],
46327 name : '-roo-edit-' + i,
46329 stylename : item.style ? item.style : false,
46330 displayField: item.displayField ? item.displayField : 'val',
46331 valueField : 'val',
46333 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46335 triggerAction: 'all',
46336 emptyText:'Select',
46337 selectOnFocus:true,
46338 width: item.width ? item.width : 130,
46340 'select': function(c, r, i) {
46342 tb.selectedNode.style[c.stylename] = r.get('val');
46345 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46354 tb.addField( new Roo.form.TextField({
46357 //allowBlank:false,
46362 tb.addField( new Roo.form.TextField({
46363 name: '-roo-edit-' + i,
46370 'change' : function(f, nv, ov) {
46371 tb.selectedNode.setAttribute(f.attrname, nv);
46372 editorcore.syncValue();
46385 text: 'Stylesheets',
46388 click : function ()
46390 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46398 text: 'Remove Tag',
46401 click : function ()
46404 // undo does not work.
46406 var sn = tb.selectedNode;
46408 var pn = sn.parentNode;
46410 var stn = sn.childNodes[0];
46411 var en = sn.childNodes[sn.childNodes.length - 1 ];
46412 while (sn.childNodes.length) {
46413 var node = sn.childNodes[0];
46414 sn.removeChild(node);
46416 pn.insertBefore(node, sn);
46419 pn.removeChild(sn);
46420 var range = editorcore.createRange();
46422 range.setStart(stn,0);
46423 range.setEnd(en,0); //????
46424 //range.selectNode(sel);
46427 var selection = editorcore.getSelection();
46428 selection.removeAllRanges();
46429 selection.addRange(range);
46433 //_this.updateToolbar(null, null, pn);
46434 _this.updateToolbar(null, null, null);
46435 _this.footDisp.dom.innerHTML = '';
46445 tb.el.on('click', function(e){
46446 e.preventDefault(); // what does this do?
46448 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46451 // dont need to disable them... as they will get hidden
46456 buildFooter : function()
46459 var fel = this.editor.wrap.createChild();
46460 this.footer = new Roo.Toolbar(fel);
46461 // toolbar has scrolly on left / right?
46462 var footDisp= new Roo.Toolbar.Fill();
46468 handler : function() {
46469 _t.footDisp.scrollTo('left',0,true)
46473 this.footer.add( footDisp );
46478 handler : function() {
46480 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46484 var fel = Roo.get(footDisp.el);
46485 fel.addClass('x-editor-context');
46486 this.footDispWrap = fel;
46487 this.footDispWrap.overflow = 'hidden';
46489 this.footDisp = fel.createChild();
46490 this.footDispWrap.on('click', this.onContextClick, this)
46494 onContextClick : function (ev,dom)
46496 ev.preventDefault();
46497 var cn = dom.className;
46499 if (!cn.match(/x-ed-loc-/)) {
46502 var n = cn.split('-').pop();
46503 var ans = this.footerEls;
46507 var range = this.editorcore.createRange();
46509 range.selectNodeContents(sel);
46510 //range.selectNode(sel);
46513 var selection = this.editorcore.getSelection();
46514 selection.removeAllRanges();
46515 selection.addRange(range);
46519 this.updateToolbar(null, null, sel);
46536 * Ext JS Library 1.1.1
46537 * Copyright(c) 2006-2007, Ext JS, LLC.
46539 * Originally Released Under LGPL - original licence link has changed is not relivant.
46542 * <script type="text/javascript">
46546 * @class Roo.form.BasicForm
46547 * @extends Roo.util.Observable
46548 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46550 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46551 * @param {Object} config Configuration options
46553 Roo.form.BasicForm = function(el, config){
46554 this.allItems = [];
46555 this.childForms = [];
46556 Roo.apply(this, config);
46558 * The Roo.form.Field items in this form.
46559 * @type MixedCollection
46563 this.items = new Roo.util.MixedCollection(false, function(o){
46564 return o.id || (o.id = Roo.id());
46568 * @event beforeaction
46569 * Fires before any action is performed. Return false to cancel the action.
46570 * @param {Form} this
46571 * @param {Action} action The action to be performed
46573 beforeaction: true,
46575 * @event actionfailed
46576 * Fires when an action fails.
46577 * @param {Form} this
46578 * @param {Action} action The action that failed
46580 actionfailed : true,
46582 * @event actioncomplete
46583 * Fires when an action is completed.
46584 * @param {Form} this
46585 * @param {Action} action The action that completed
46587 actioncomplete : true
46592 Roo.form.BasicForm.superclass.constructor.call(this);
46595 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46597 * @cfg {String} method
46598 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46601 * @cfg {DataReader} reader
46602 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46603 * This is optional as there is built-in support for processing JSON.
46606 * @cfg {DataReader} errorReader
46607 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46608 * This is completely optional as there is built-in support for processing JSON.
46611 * @cfg {String} url
46612 * The URL to use for form actions if one isn't supplied in the action options.
46615 * @cfg {Boolean} fileUpload
46616 * Set to true if this form is a file upload.
46620 * @cfg {Object} baseParams
46621 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46626 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46631 activeAction : null,
46634 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46635 * or setValues() data instead of when the form was first created.
46637 trackResetOnLoad : false,
46641 * childForms - used for multi-tab forms
46644 childForms : false,
46647 * allItems - full list of fields.
46653 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46654 * element by passing it or its id or mask the form itself by passing in true.
46657 waitMsgTarget : false,
46660 initEl : function(el){
46661 this.el = Roo.get(el);
46662 this.id = this.el.id || Roo.id();
46663 this.el.on('submit', this.onSubmit, this);
46664 this.el.addClass('x-form');
46668 onSubmit : function(e){
46673 * Returns true if client-side validation on the form is successful.
46676 isValid : function(){
46678 this.items.each(function(f){
46687 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46690 isDirty : function(){
46692 this.items.each(function(f){
46702 * Returns true if any fields in this form have changed since their original load. (New version)
46706 hasChanged : function()
46709 this.items.each(function(f){
46710 if(f.hasChanged()){
46719 * Resets all hasChanged to 'false' -
46720 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46721 * So hasChanged storage is only to be used for this purpose
46724 resetHasChanged : function()
46726 this.items.each(function(f){
46727 f.resetHasChanged();
46734 * Performs a predefined action (submit or load) or custom actions you define on this form.
46735 * @param {String} actionName The name of the action type
46736 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46737 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46738 * accept other config options):
46740 Property Type Description
46741 ---------------- --------------- ----------------------------------------------------------------------------------
46742 url String The url for the action (defaults to the form's url)
46743 method String The form method to use (defaults to the form's method, or POST if not defined)
46744 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46745 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46746 validate the form on the client (defaults to false)
46748 * @return {BasicForm} this
46750 doAction : function(action, options){
46751 if(typeof action == 'string'){
46752 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46754 if(this.fireEvent('beforeaction', this, action) !== false){
46755 this.beforeAction(action);
46756 action.run.defer(100, action);
46762 * Shortcut to do a submit action.
46763 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46764 * @return {BasicForm} this
46766 submit : function(options){
46767 this.doAction('submit', options);
46772 * Shortcut to do a load action.
46773 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46774 * @return {BasicForm} this
46776 load : function(options){
46777 this.doAction('load', options);
46782 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46783 * @param {Record} record The record to edit
46784 * @return {BasicForm} this
46786 updateRecord : function(record){
46787 record.beginEdit();
46788 var fs = record.fields;
46789 fs.each(function(f){
46790 var field = this.findField(f.name);
46792 record.set(f.name, field.getValue());
46800 * Loads an Roo.data.Record into this form.
46801 * @param {Record} record The record to load
46802 * @return {BasicForm} this
46804 loadRecord : function(record){
46805 this.setValues(record.data);
46810 beforeAction : function(action){
46811 var o = action.options;
46814 if(this.waitMsgTarget === true){
46815 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46816 }else if(this.waitMsgTarget){
46817 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46818 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46820 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46826 afterAction : function(action, success){
46827 this.activeAction = null;
46828 var o = action.options;
46830 if(this.waitMsgTarget === true){
46832 }else if(this.waitMsgTarget){
46833 this.waitMsgTarget.unmask();
46835 Roo.MessageBox.updateProgress(1);
46836 Roo.MessageBox.hide();
46843 Roo.callback(o.success, o.scope, [this, action]);
46844 this.fireEvent('actioncomplete', this, action);
46848 // failure condition..
46849 // we have a scenario where updates need confirming.
46850 // eg. if a locking scenario exists..
46851 // we look for { errors : { needs_confirm : true }} in the response.
46853 (typeof(action.result) != 'undefined') &&
46854 (typeof(action.result.errors) != 'undefined') &&
46855 (typeof(action.result.errors.needs_confirm) != 'undefined')
46858 Roo.MessageBox.confirm(
46859 "Change requires confirmation",
46860 action.result.errorMsg,
46865 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46875 Roo.callback(o.failure, o.scope, [this, action]);
46876 // show an error message if no failed handler is set..
46877 if (!this.hasListener('actionfailed')) {
46878 Roo.MessageBox.alert("Error",
46879 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46880 action.result.errorMsg :
46881 "Saving Failed, please check your entries or try again"
46885 this.fireEvent('actionfailed', this, action);
46891 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46892 * @param {String} id The value to search for
46895 findField : function(id){
46896 var field = this.items.get(id);
46898 this.items.each(function(f){
46899 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46905 return field || null;
46909 * Add a secondary form to this one,
46910 * Used to provide tabbed forms. One form is primary, with hidden values
46911 * which mirror the elements from the other forms.
46913 * @param {Roo.form.Form} form to add.
46916 addForm : function(form)
46919 if (this.childForms.indexOf(form) > -1) {
46923 this.childForms.push(form);
46925 Roo.each(form.allItems, function (fe) {
46927 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46928 if (this.findField(n)) { // already added..
46931 var add = new Roo.form.Hidden({
46934 add.render(this.el);
46941 * Mark fields in this form invalid in bulk.
46942 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46943 * @return {BasicForm} this
46945 markInvalid : function(errors){
46946 if(errors instanceof Array){
46947 for(var i = 0, len = errors.length; i < len; i++){
46948 var fieldError = errors[i];
46949 var f = this.findField(fieldError.id);
46951 f.markInvalid(fieldError.msg);
46957 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46958 field.markInvalid(errors[id]);
46962 Roo.each(this.childForms || [], function (f) {
46963 f.markInvalid(errors);
46970 * Set values for fields in this form in bulk.
46971 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46972 * @return {BasicForm} this
46974 setValues : function(values){
46975 if(values instanceof Array){ // array of objects
46976 for(var i = 0, len = values.length; i < len; i++){
46978 var f = this.findField(v.id);
46980 f.setValue(v.value);
46981 if(this.trackResetOnLoad){
46982 f.originalValue = f.getValue();
46986 }else{ // object hash
46989 if(typeof values[id] != 'function' && (field = this.findField(id))){
46991 if (field.setFromData &&
46992 field.valueField &&
46993 field.displayField &&
46994 // combos' with local stores can
46995 // be queried via setValue()
46996 // to set their value..
46997 (field.store && !field.store.isLocal)
47001 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47002 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47003 field.setFromData(sd);
47006 field.setValue(values[id]);
47010 if(this.trackResetOnLoad){
47011 field.originalValue = field.getValue();
47016 this.resetHasChanged();
47019 Roo.each(this.childForms || [], function (f) {
47020 f.setValues(values);
47021 f.resetHasChanged();
47028 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47029 * they are returned as an array.
47030 * @param {Boolean} asString
47033 getValues : function(asString){
47034 if (this.childForms) {
47035 // copy values from the child forms
47036 Roo.each(this.childForms, function (f) {
47037 this.setValues(f.getValues());
47043 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47044 if(asString === true){
47047 return Roo.urlDecode(fs);
47051 * Returns the fields in this form as an object with key/value pairs.
47052 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47055 getFieldValues : function(with_hidden)
47057 if (this.childForms) {
47058 // copy values from the child forms
47059 // should this call getFieldValues - probably not as we do not currently copy
47060 // hidden fields when we generate..
47061 Roo.each(this.childForms, function (f) {
47062 this.setValues(f.getValues());
47067 this.items.each(function(f){
47068 if (!f.getName()) {
47071 var v = f.getValue();
47072 if (f.inputType =='radio') {
47073 if (typeof(ret[f.getName()]) == 'undefined') {
47074 ret[f.getName()] = ''; // empty..
47077 if (!f.el.dom.checked) {
47081 v = f.el.dom.value;
47085 // not sure if this supported any more..
47086 if ((typeof(v) == 'object') && f.getRawValue) {
47087 v = f.getRawValue() ; // dates..
47089 // combo boxes where name != hiddenName...
47090 if (f.name != f.getName()) {
47091 ret[f.name] = f.getRawValue();
47093 ret[f.getName()] = v;
47100 * Clears all invalid messages in this form.
47101 * @return {BasicForm} this
47103 clearInvalid : function(){
47104 this.items.each(function(f){
47108 Roo.each(this.childForms || [], function (f) {
47117 * Resets this form.
47118 * @return {BasicForm} this
47120 reset : function(){
47121 this.items.each(function(f){
47125 Roo.each(this.childForms || [], function (f) {
47128 this.resetHasChanged();
47134 * Add Roo.form components to this form.
47135 * @param {Field} field1
47136 * @param {Field} field2 (optional)
47137 * @param {Field} etc (optional)
47138 * @return {BasicForm} this
47141 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47147 * Removes a field from the items collection (does NOT remove its markup).
47148 * @param {Field} field
47149 * @return {BasicForm} this
47151 remove : function(field){
47152 this.items.remove(field);
47157 * Looks at the fields in this form, checks them for an id attribute,
47158 * and calls applyTo on the existing dom element with that id.
47159 * @return {BasicForm} this
47161 render : function(){
47162 this.items.each(function(f){
47163 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47171 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47172 * @param {Object} values
47173 * @return {BasicForm} this
47175 applyToFields : function(o){
47176 this.items.each(function(f){
47183 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47184 * @param {Object} values
47185 * @return {BasicForm} this
47187 applyIfToFields : function(o){
47188 this.items.each(function(f){
47196 Roo.BasicForm = Roo.form.BasicForm;/*
47198 * Ext JS Library 1.1.1
47199 * Copyright(c) 2006-2007, Ext JS, LLC.
47201 * Originally Released Under LGPL - original licence link has changed is not relivant.
47204 * <script type="text/javascript">
47208 * @class Roo.form.Form
47209 * @extends Roo.form.BasicForm
47210 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47212 * @param {Object} config Configuration options
47214 Roo.form.Form = function(config){
47216 if (config.items) {
47217 xitems = config.items;
47218 delete config.items;
47222 Roo.form.Form.superclass.constructor.call(this, null, config);
47223 this.url = this.url || this.action;
47225 this.root = new Roo.form.Layout(Roo.applyIf({
47229 this.active = this.root;
47231 * Array of all the buttons that have been added to this form via {@link addButton}
47235 this.allItems = [];
47238 * @event clientvalidation
47239 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47240 * @param {Form} this
47241 * @param {Boolean} valid true if the form has passed client-side validation
47243 clientvalidation: true,
47246 * Fires when the form is rendered
47247 * @param {Roo.form.Form} form
47252 if (this.progressUrl) {
47253 // push a hidden field onto the list of fields..
47257 name : 'UPLOAD_IDENTIFIER'
47262 Roo.each(xitems, this.addxtype, this);
47268 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47270 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47273 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47276 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47278 buttonAlign:'center',
47281 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47286 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47287 * This property cascades to child containers if not set.
47292 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47293 * fires a looping event with that state. This is required to bind buttons to the valid
47294 * state using the config value formBind:true on the button.
47296 monitorValid : false,
47299 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47304 * @cfg {String} progressUrl - Url to return progress data
47307 progressUrl : false,
47310 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47311 * fields are added and the column is closed. If no fields are passed the column remains open
47312 * until end() is called.
47313 * @param {Object} config The config to pass to the column
47314 * @param {Field} field1 (optional)
47315 * @param {Field} field2 (optional)
47316 * @param {Field} etc (optional)
47317 * @return Column The column container object
47319 column : function(c){
47320 var col = new Roo.form.Column(c);
47322 if(arguments.length > 1){ // duplicate code required because of Opera
47323 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47330 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47331 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47332 * until end() is called.
47333 * @param {Object} config The config to pass to the fieldset
47334 * @param {Field} field1 (optional)
47335 * @param {Field} field2 (optional)
47336 * @param {Field} etc (optional)
47337 * @return FieldSet The fieldset container object
47339 fieldset : function(c){
47340 var fs = new Roo.form.FieldSet(c);
47342 if(arguments.length > 1){ // duplicate code required because of Opera
47343 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47350 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47351 * fields are added and the container is closed. If no fields are passed the container remains open
47352 * until end() is called.
47353 * @param {Object} config The config to pass to the Layout
47354 * @param {Field} field1 (optional)
47355 * @param {Field} field2 (optional)
47356 * @param {Field} etc (optional)
47357 * @return Layout The container object
47359 container : function(c){
47360 var l = new Roo.form.Layout(c);
47362 if(arguments.length > 1){ // duplicate code required because of Opera
47363 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47370 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47371 * @param {Object} container A Roo.form.Layout or subclass of Layout
47372 * @return {Form} this
47374 start : function(c){
47375 // cascade label info
47376 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47377 this.active.stack.push(c);
47378 c.ownerCt = this.active;
47384 * Closes the current open container
47385 * @return {Form} this
47388 if(this.active == this.root){
47391 this.active = this.active.ownerCt;
47396 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47397 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47398 * as the label of the field.
47399 * @param {Field} field1
47400 * @param {Field} field2 (optional)
47401 * @param {Field} etc. (optional)
47402 * @return {Form} this
47405 this.active.stack.push.apply(this.active.stack, arguments);
47406 this.allItems.push.apply(this.allItems,arguments);
47408 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47409 if(a[i].isFormField){
47414 Roo.form.Form.superclass.add.apply(this, r);
47424 * Find any element that has been added to a form, using it's ID or name
47425 * This can include framesets, columns etc. along with regular fields..
47426 * @param {String} id - id or name to find.
47428 * @return {Element} e - or false if nothing found.
47430 findbyId : function(id)
47436 Roo.each(this.allItems, function(f){
47437 if (f.id == id || f.name == id ){
47448 * Render this form into the passed container. This should only be called once!
47449 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47450 * @return {Form} this
47452 render : function(ct)
47458 var o = this.autoCreate || {
47460 method : this.method || 'POST',
47461 id : this.id || Roo.id()
47463 this.initEl(ct.createChild(o));
47465 this.root.render(this.el);
47469 this.items.each(function(f){
47470 f.render('x-form-el-'+f.id);
47473 if(this.buttons.length > 0){
47474 // tables are required to maintain order and for correct IE layout
47475 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47476 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47477 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47479 var tr = tb.getElementsByTagName('tr')[0];
47480 for(var i = 0, len = this.buttons.length; i < len; i++) {
47481 var b = this.buttons[i];
47482 var td = document.createElement('td');
47483 td.className = 'x-form-btn-td';
47484 b.render(tr.appendChild(td));
47487 if(this.monitorValid){ // initialize after render
47488 this.startMonitoring();
47490 this.fireEvent('rendered', this);
47495 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47496 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47497 * object or a valid Roo.DomHelper element config
47498 * @param {Function} handler The function called when the button is clicked
47499 * @param {Object} scope (optional) The scope of the handler function
47500 * @return {Roo.Button}
47502 addButton : function(config, handler, scope){
47506 minWidth: this.minButtonWidth,
47509 if(typeof config == "string"){
47512 Roo.apply(bc, config);
47514 var btn = new Roo.Button(null, bc);
47515 this.buttons.push(btn);
47520 * Adds a series of form elements (using the xtype property as the factory method.
47521 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47522 * @param {Object} config
47525 addxtype : function()
47527 var ar = Array.prototype.slice.call(arguments, 0);
47529 for(var i = 0; i < ar.length; i++) {
47531 continue; // skip -- if this happends something invalid got sent, we
47532 // should ignore it, as basically that interface element will not show up
47533 // and that should be pretty obvious!!
47536 if (Roo.form[ar[i].xtype]) {
47538 var fe = Roo.factory(ar[i], Roo.form);
47544 fe.store.form = this;
47549 this.allItems.push(fe);
47550 if (fe.items && fe.addxtype) {
47551 fe.addxtype.apply(fe, fe.items);
47561 // console.log('adding ' + ar[i].xtype);
47563 if (ar[i].xtype == 'Button') {
47564 //console.log('adding button');
47565 //console.log(ar[i]);
47566 this.addButton(ar[i]);
47567 this.allItems.push(fe);
47571 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47572 alert('end is not supported on xtype any more, use items');
47574 // //console.log('adding end');
47582 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47583 * option "monitorValid"
47585 startMonitoring : function(){
47588 Roo.TaskMgr.start({
47589 run : this.bindHandler,
47590 interval : this.monitorPoll || 200,
47597 * Stops monitoring of the valid state of this form
47599 stopMonitoring : function(){
47600 this.bound = false;
47604 bindHandler : function(){
47606 return false; // stops binding
47609 this.items.each(function(f){
47610 if(!f.isValid(true)){
47615 for(var i = 0, len = this.buttons.length; i < len; i++){
47616 var btn = this.buttons[i];
47617 if(btn.formBind === true && btn.disabled === valid){
47618 btn.setDisabled(!valid);
47621 this.fireEvent('clientvalidation', this, valid);
47635 Roo.Form = Roo.form.Form;
47638 * Ext JS Library 1.1.1
47639 * Copyright(c) 2006-2007, Ext JS, LLC.
47641 * Originally Released Under LGPL - original licence link has changed is not relivant.
47644 * <script type="text/javascript">
47647 // as we use this in bootstrap.
47648 Roo.namespace('Roo.form');
47650 * @class Roo.form.Action
47651 * Internal Class used to handle form actions
47653 * @param {Roo.form.BasicForm} el The form element or its id
47654 * @param {Object} config Configuration options
47659 // define the action interface
47660 Roo.form.Action = function(form, options){
47662 this.options = options || {};
47665 * Client Validation Failed
47668 Roo.form.Action.CLIENT_INVALID = 'client';
47670 * Server Validation Failed
47673 Roo.form.Action.SERVER_INVALID = 'server';
47675 * Connect to Server Failed
47678 Roo.form.Action.CONNECT_FAILURE = 'connect';
47680 * Reading Data from Server Failed
47683 Roo.form.Action.LOAD_FAILURE = 'load';
47685 Roo.form.Action.prototype = {
47687 failureType : undefined,
47688 response : undefined,
47689 result : undefined,
47691 // interface method
47692 run : function(options){
47696 // interface method
47697 success : function(response){
47701 // interface method
47702 handleResponse : function(response){
47706 // default connection failure
47707 failure : function(response){
47709 this.response = response;
47710 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47711 this.form.afterAction(this, false);
47714 processResponse : function(response){
47715 this.response = response;
47716 if(!response.responseText){
47719 this.result = this.handleResponse(response);
47720 return this.result;
47723 // utility functions used internally
47724 getUrl : function(appendParams){
47725 var url = this.options.url || this.form.url || this.form.el.dom.action;
47727 var p = this.getParams();
47729 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47735 getMethod : function(){
47736 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47739 getParams : function(){
47740 var bp = this.form.baseParams;
47741 var p = this.options.params;
47743 if(typeof p == "object"){
47744 p = Roo.urlEncode(Roo.applyIf(p, bp));
47745 }else if(typeof p == 'string' && bp){
47746 p += '&' + Roo.urlEncode(bp);
47749 p = Roo.urlEncode(bp);
47754 createCallback : function(){
47756 success: this.success,
47757 failure: this.failure,
47759 timeout: (this.form.timeout*1000),
47760 upload: this.form.fileUpload ? this.success : undefined
47765 Roo.form.Action.Submit = function(form, options){
47766 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47769 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47772 haveProgress : false,
47773 uploadComplete : false,
47775 // uploadProgress indicator.
47776 uploadProgress : function()
47778 if (!this.form.progressUrl) {
47782 if (!this.haveProgress) {
47783 Roo.MessageBox.progress("Uploading", "Uploading");
47785 if (this.uploadComplete) {
47786 Roo.MessageBox.hide();
47790 this.haveProgress = true;
47792 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47794 var c = new Roo.data.Connection();
47796 url : this.form.progressUrl,
47801 success : function(req){
47802 //console.log(data);
47806 rdata = Roo.decode(req.responseText)
47808 Roo.log("Invalid data from server..");
47812 if (!rdata || !rdata.success) {
47814 Roo.MessageBox.alert(Roo.encode(rdata));
47817 var data = rdata.data;
47819 if (this.uploadComplete) {
47820 Roo.MessageBox.hide();
47825 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47826 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47829 this.uploadProgress.defer(2000,this);
47832 failure: function(data) {
47833 Roo.log('progress url failed ');
47844 // run get Values on the form, so it syncs any secondary forms.
47845 this.form.getValues();
47847 var o = this.options;
47848 var method = this.getMethod();
47849 var isPost = method == 'POST';
47850 if(o.clientValidation === false || this.form.isValid()){
47852 if (this.form.progressUrl) {
47853 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47854 (new Date() * 1) + '' + Math.random());
47859 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47860 form:this.form.el.dom,
47861 url:this.getUrl(!isPost),
47863 params:isPost ? this.getParams() : null,
47864 isUpload: this.form.fileUpload
47867 this.uploadProgress();
47869 }else if (o.clientValidation !== false){ // client validation failed
47870 this.failureType = Roo.form.Action.CLIENT_INVALID;
47871 this.form.afterAction(this, false);
47875 success : function(response)
47877 this.uploadComplete= true;
47878 if (this.haveProgress) {
47879 Roo.MessageBox.hide();
47883 var result = this.processResponse(response);
47884 if(result === true || result.success){
47885 this.form.afterAction(this, true);
47889 this.form.markInvalid(result.errors);
47890 this.failureType = Roo.form.Action.SERVER_INVALID;
47892 this.form.afterAction(this, false);
47894 failure : function(response)
47896 this.uploadComplete= true;
47897 if (this.haveProgress) {
47898 Roo.MessageBox.hide();
47901 this.response = response;
47902 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47903 this.form.afterAction(this, false);
47906 handleResponse : function(response){
47907 if(this.form.errorReader){
47908 var rs = this.form.errorReader.read(response);
47911 for(var i = 0, len = rs.records.length; i < len; i++) {
47912 var r = rs.records[i];
47913 errors[i] = r.data;
47916 if(errors.length < 1){
47920 success : rs.success,
47926 ret = Roo.decode(response.responseText);
47930 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47940 Roo.form.Action.Load = function(form, options){
47941 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47942 this.reader = this.form.reader;
47945 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47950 Roo.Ajax.request(Roo.apply(
47951 this.createCallback(), {
47952 method:this.getMethod(),
47953 url:this.getUrl(false),
47954 params:this.getParams()
47958 success : function(response){
47960 var result = this.processResponse(response);
47961 if(result === true || !result.success || !result.data){
47962 this.failureType = Roo.form.Action.LOAD_FAILURE;
47963 this.form.afterAction(this, false);
47966 this.form.clearInvalid();
47967 this.form.setValues(result.data);
47968 this.form.afterAction(this, true);
47971 handleResponse : function(response){
47972 if(this.form.reader){
47973 var rs = this.form.reader.read(response);
47974 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47976 success : rs.success,
47980 return Roo.decode(response.responseText);
47984 Roo.form.Action.ACTION_TYPES = {
47985 'load' : Roo.form.Action.Load,
47986 'submit' : Roo.form.Action.Submit
47989 * Ext JS Library 1.1.1
47990 * Copyright(c) 2006-2007, Ext JS, LLC.
47992 * Originally Released Under LGPL - original licence link has changed is not relivant.
47995 * <script type="text/javascript">
47999 * @class Roo.form.Layout
48000 * @extends Roo.Component
48001 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48003 * @param {Object} config Configuration options
48005 Roo.form.Layout = function(config){
48007 if (config.items) {
48008 xitems = config.items;
48009 delete config.items;
48011 Roo.form.Layout.superclass.constructor.call(this, config);
48013 Roo.each(xitems, this.addxtype, this);
48017 Roo.extend(Roo.form.Layout, Roo.Component, {
48019 * @cfg {String/Object} autoCreate
48020 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48023 * @cfg {String/Object/Function} style
48024 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48025 * a function which returns such a specification.
48028 * @cfg {String} labelAlign
48029 * Valid values are "left," "top" and "right" (defaults to "left")
48032 * @cfg {Number} labelWidth
48033 * Fixed width in pixels of all field labels (defaults to undefined)
48036 * @cfg {Boolean} clear
48037 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48041 * @cfg {String} labelSeparator
48042 * The separator to use after field labels (defaults to ':')
48044 labelSeparator : ':',
48046 * @cfg {Boolean} hideLabels
48047 * True to suppress the display of field labels in this layout (defaults to false)
48049 hideLabels : false,
48052 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48057 onRender : function(ct, position){
48058 if(this.el){ // from markup
48059 this.el = Roo.get(this.el);
48060 }else { // generate
48061 var cfg = this.getAutoCreate();
48062 this.el = ct.createChild(cfg, position);
48065 this.el.applyStyles(this.style);
48067 if(this.labelAlign){
48068 this.el.addClass('x-form-label-'+this.labelAlign);
48070 if(this.hideLabels){
48071 this.labelStyle = "display:none";
48072 this.elementStyle = "padding-left:0;";
48074 if(typeof this.labelWidth == 'number'){
48075 this.labelStyle = "width:"+this.labelWidth+"px;";
48076 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48078 if(this.labelAlign == 'top'){
48079 this.labelStyle = "width:auto;";
48080 this.elementStyle = "padding-left:0;";
48083 var stack = this.stack;
48084 var slen = stack.length;
48086 if(!this.fieldTpl){
48087 var t = new Roo.Template(
48088 '<div class="x-form-item {5}">',
48089 '<label for="{0}" style="{2}">{1}{4}</label>',
48090 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48092 '</div><div class="x-form-clear-left"></div>'
48094 t.disableFormats = true;
48096 Roo.form.Layout.prototype.fieldTpl = t;
48098 for(var i = 0; i < slen; i++) {
48099 if(stack[i].isFormField){
48100 this.renderField(stack[i]);
48102 this.renderComponent(stack[i]);
48107 this.el.createChild({cls:'x-form-clear'});
48112 renderField : function(f){
48113 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48116 f.labelStyle||this.labelStyle||'', //2
48117 this.elementStyle||'', //3
48118 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48119 f.itemCls||this.itemCls||'' //5
48120 ], true).getPrevSibling());
48124 renderComponent : function(c){
48125 c.render(c.isLayout ? this.el : this.el.createChild());
48128 * Adds a object form elements (using the xtype property as the factory method.)
48129 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48130 * @param {Object} config
48132 addxtype : function(o)
48134 // create the lement.
48135 o.form = this.form;
48136 var fe = Roo.factory(o, Roo.form);
48137 this.form.allItems.push(fe);
48138 this.stack.push(fe);
48140 if (fe.isFormField) {
48141 this.form.items.add(fe);
48149 * @class Roo.form.Column
48150 * @extends Roo.form.Layout
48151 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48153 * @param {Object} config Configuration options
48155 Roo.form.Column = function(config){
48156 Roo.form.Column.superclass.constructor.call(this, config);
48159 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48161 * @cfg {Number/String} width
48162 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48165 * @cfg {String/Object} autoCreate
48166 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48170 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48173 onRender : function(ct, position){
48174 Roo.form.Column.superclass.onRender.call(this, ct, position);
48176 this.el.setWidth(this.width);
48183 * @class Roo.form.Row
48184 * @extends Roo.form.Layout
48185 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48187 * @param {Object} config Configuration options
48191 Roo.form.Row = function(config){
48192 Roo.form.Row.superclass.constructor.call(this, config);
48195 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48197 * @cfg {Number/String} width
48198 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48201 * @cfg {Number/String} height
48202 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48204 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48208 onRender : function(ct, position){
48209 //console.log('row render');
48211 var t = new Roo.Template(
48212 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48213 '<label for="{0}" style="{2}">{1}{4}</label>',
48214 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48218 t.disableFormats = true;
48220 Roo.form.Layout.prototype.rowTpl = t;
48222 this.fieldTpl = this.rowTpl;
48224 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48225 var labelWidth = 100;
48227 if ((this.labelAlign != 'top')) {
48228 if (typeof this.labelWidth == 'number') {
48229 labelWidth = this.labelWidth
48231 this.padWidth = 20 + labelWidth;
48235 Roo.form.Column.superclass.onRender.call(this, ct, position);
48237 this.el.setWidth(this.width);
48240 this.el.setHeight(this.height);
48245 renderField : function(f){
48246 f.fieldEl = this.fieldTpl.append(this.el, [
48247 f.id, f.fieldLabel,
48248 f.labelStyle||this.labelStyle||'',
48249 this.elementStyle||'',
48250 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48251 f.itemCls||this.itemCls||'',
48252 f.width ? f.width + this.padWidth : 160 + this.padWidth
48259 * @class Roo.form.FieldSet
48260 * @extends Roo.form.Layout
48261 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48263 * @param {Object} config Configuration options
48265 Roo.form.FieldSet = function(config){
48266 Roo.form.FieldSet.superclass.constructor.call(this, config);
48269 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48271 * @cfg {String} legend
48272 * The text to display as the legend for the FieldSet (defaults to '')
48275 * @cfg {String/Object} autoCreate
48276 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48280 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48283 onRender : function(ct, position){
48284 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48286 this.setLegend(this.legend);
48291 setLegend : function(text){
48293 this.el.child('legend').update(text);
48298 * Ext JS Library 1.1.1
48299 * Copyright(c) 2006-2007, Ext JS, LLC.
48301 * Originally Released Under LGPL - original licence link has changed is not relivant.
48304 * <script type="text/javascript">
48307 * @class Roo.form.VTypes
48308 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48311 Roo.form.VTypes = function(){
48312 // closure these in so they are only created once.
48313 var alpha = /^[a-zA-Z_]+$/;
48314 var alphanum = /^[a-zA-Z0-9_]+$/;
48315 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48316 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48318 // All these messages and functions are configurable
48321 * The function used to validate email addresses
48322 * @param {String} value The email address
48324 'email' : function(v){
48325 return email.test(v);
48328 * The error text to display when the email validation function returns false
48331 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48333 * The keystroke filter mask to be applied on email input
48336 'emailMask' : /[a-z0-9_\.\-@]/i,
48339 * The function used to validate URLs
48340 * @param {String} value The URL
48342 'url' : function(v){
48343 return url.test(v);
48346 * The error text to display when the url validation function returns false
48349 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48352 * The function used to validate alpha values
48353 * @param {String} value The value
48355 'alpha' : function(v){
48356 return alpha.test(v);
48359 * The error text to display when the alpha validation function returns false
48362 'alphaText' : 'This field should only contain letters and _',
48364 * The keystroke filter mask to be applied on alpha input
48367 'alphaMask' : /[a-z_]/i,
48370 * The function used to validate alphanumeric values
48371 * @param {String} value The value
48373 'alphanum' : function(v){
48374 return alphanum.test(v);
48377 * The error text to display when the alphanumeric validation function returns false
48380 'alphanumText' : 'This field should only contain letters, numbers and _',
48382 * The keystroke filter mask to be applied on alphanumeric input
48385 'alphanumMask' : /[a-z0-9_]/i
48387 }();//<script type="text/javascript">
48390 * @class Roo.form.FCKeditor
48391 * @extends Roo.form.TextArea
48392 * Wrapper around the FCKEditor http://www.fckeditor.net
48394 * Creates a new FCKeditor
48395 * @param {Object} config Configuration options
48397 Roo.form.FCKeditor = function(config){
48398 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48401 * @event editorinit
48402 * Fired when the editor is initialized - you can add extra handlers here..
48403 * @param {FCKeditor} this
48404 * @param {Object} the FCK object.
48411 Roo.form.FCKeditor.editors = { };
48412 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48414 //defaultAutoCreate : {
48415 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48419 * @cfg {Object} fck options - see fck manual for details.
48424 * @cfg {Object} fck toolbar set (Basic or Default)
48426 toolbarSet : 'Basic',
48428 * @cfg {Object} fck BasePath
48430 basePath : '/fckeditor/',
48438 onRender : function(ct, position)
48441 this.defaultAutoCreate = {
48443 style:"width:300px;height:60px;",
48444 autocomplete: "new-password"
48447 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48450 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48451 if(this.preventScrollbars){
48452 this.el.setStyle("overflow", "hidden");
48454 this.el.setHeight(this.growMin);
48457 //console.log('onrender' + this.getId() );
48458 Roo.form.FCKeditor.editors[this.getId()] = this;
48461 this.replaceTextarea() ;
48465 getEditor : function() {
48466 return this.fckEditor;
48469 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48470 * @param {Mixed} value The value to set
48474 setValue : function(value)
48476 //console.log('setValue: ' + value);
48478 if(typeof(value) == 'undefined') { // not sure why this is happending...
48481 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48483 //if(!this.el || !this.getEditor()) {
48484 // this.value = value;
48485 //this.setValue.defer(100,this,[value]);
48489 if(!this.getEditor()) {
48493 this.getEditor().SetData(value);
48500 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48501 * @return {Mixed} value The field value
48503 getValue : function()
48506 if (this.frame && this.frame.dom.style.display == 'none') {
48507 return Roo.form.FCKeditor.superclass.getValue.call(this);
48510 if(!this.el || !this.getEditor()) {
48512 // this.getValue.defer(100,this);
48517 var value=this.getEditor().GetData();
48518 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48519 return Roo.form.FCKeditor.superclass.getValue.call(this);
48525 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48526 * @return {Mixed} value The field value
48528 getRawValue : function()
48530 if (this.frame && this.frame.dom.style.display == 'none') {
48531 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48534 if(!this.el || !this.getEditor()) {
48535 //this.getRawValue.defer(100,this);
48542 var value=this.getEditor().GetData();
48543 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48544 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48548 setSize : function(w,h) {
48552 //if (this.frame && this.frame.dom.style.display == 'none') {
48553 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48556 //if(!this.el || !this.getEditor()) {
48557 // this.setSize.defer(100,this, [w,h]);
48563 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48565 this.frame.dom.setAttribute('width', w);
48566 this.frame.dom.setAttribute('height', h);
48567 this.frame.setSize(w,h);
48571 toggleSourceEdit : function(value) {
48575 this.el.dom.style.display = value ? '' : 'none';
48576 this.frame.dom.style.display = value ? 'none' : '';
48581 focus: function(tag)
48583 if (this.frame.dom.style.display == 'none') {
48584 return Roo.form.FCKeditor.superclass.focus.call(this);
48586 if(!this.el || !this.getEditor()) {
48587 this.focus.defer(100,this, [tag]);
48594 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48595 this.getEditor().Focus();
48597 if (!this.getEditor().Selection.GetSelection()) {
48598 this.focus.defer(100,this, [tag]);
48603 var r = this.getEditor().EditorDocument.createRange();
48604 r.setStart(tgs[0],0);
48605 r.setEnd(tgs[0],0);
48606 this.getEditor().Selection.GetSelection().removeAllRanges();
48607 this.getEditor().Selection.GetSelection().addRange(r);
48608 this.getEditor().Focus();
48615 replaceTextarea : function()
48617 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48620 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48622 // We must check the elements firstly using the Id and then the name.
48623 var oTextarea = document.getElementById( this.getId() );
48625 var colElementsByName = document.getElementsByName( this.getId() ) ;
48627 oTextarea.style.display = 'none' ;
48629 if ( oTextarea.tabIndex ) {
48630 this.TabIndex = oTextarea.tabIndex ;
48633 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48634 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48635 this.frame = Roo.get(this.getId() + '___Frame')
48638 _getConfigHtml : function()
48642 for ( var o in this.fckconfig ) {
48643 sConfig += sConfig.length > 0 ? '&' : '';
48644 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48647 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48651 _getIFrameHtml : function()
48653 var sFile = 'fckeditor.html' ;
48654 /* no idea what this is about..
48657 if ( (/fcksource=true/i).test( window.top.location.search ) )
48658 sFile = 'fckeditor.original.html' ;
48663 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48664 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48667 var html = '<iframe id="' + this.getId() +
48668 '___Frame" src="' + sLink +
48669 '" width="' + this.width +
48670 '" height="' + this.height + '"' +
48671 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48672 ' frameborder="0" scrolling="no"></iframe>' ;
48677 _insertHtmlBefore : function( html, element )
48679 if ( element.insertAdjacentHTML ) {
48681 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48683 var oRange = document.createRange() ;
48684 oRange.setStartBefore( element ) ;
48685 var oFragment = oRange.createContextualFragment( html );
48686 element.parentNode.insertBefore( oFragment, element ) ;
48699 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48701 function FCKeditor_OnComplete(editorInstance){
48702 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48703 f.fckEditor = editorInstance;
48704 //console.log("loaded");
48705 f.fireEvent('editorinit', f, editorInstance);
48725 //<script type="text/javascript">
48727 * @class Roo.form.GridField
48728 * @extends Roo.form.Field
48729 * Embed a grid (or editable grid into a form)
48732 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48734 * xgrid.store = Roo.data.Store
48735 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48736 * xgrid.store.reader = Roo.data.JsonReader
48740 * Creates a new GridField
48741 * @param {Object} config Configuration options
48743 Roo.form.GridField = function(config){
48744 Roo.form.GridField.superclass.constructor.call(this, config);
48748 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48750 * @cfg {Number} width - used to restrict width of grid..
48754 * @cfg {Number} height - used to restrict height of grid..
48758 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48764 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48765 * {tag: "input", type: "checkbox", autocomplete: "off"})
48767 // defaultAutoCreate : { tag: 'div' },
48768 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48770 * @cfg {String} addTitle Text to include for adding a title.
48774 onResize : function(){
48775 Roo.form.Field.superclass.onResize.apply(this, arguments);
48778 initEvents : function(){
48779 // Roo.form.Checkbox.superclass.initEvents.call(this);
48780 // has no events...
48785 getResizeEl : function(){
48789 getPositionEl : function(){
48794 onRender : function(ct, position){
48796 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48797 var style = this.style;
48800 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48801 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48802 this.viewEl = this.wrap.createChild({ tag: 'div' });
48804 this.viewEl.applyStyles(style);
48807 this.viewEl.setWidth(this.width);
48810 this.viewEl.setHeight(this.height);
48812 //if(this.inputValue !== undefined){
48813 //this.setValue(this.value);
48816 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48819 this.grid.render();
48820 this.grid.getDataSource().on('remove', this.refreshValue, this);
48821 this.grid.getDataSource().on('update', this.refreshValue, this);
48822 this.grid.on('afteredit', this.refreshValue, this);
48828 * Sets the value of the item.
48829 * @param {String} either an object or a string..
48831 setValue : function(v){
48833 v = v || []; // empty set..
48834 // this does not seem smart - it really only affects memoryproxy grids..
48835 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48836 var ds = this.grid.getDataSource();
48837 // assumes a json reader..
48839 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48840 ds.loadData( data);
48842 // clear selection so it does not get stale.
48843 if (this.grid.sm) {
48844 this.grid.sm.clearSelections();
48847 Roo.form.GridField.superclass.setValue.call(this, v);
48848 this.refreshValue();
48849 // should load data in the grid really....
48853 refreshValue: function() {
48855 this.grid.getDataSource().each(function(r) {
48858 this.el.dom.value = Roo.encode(val);
48866 * Ext JS Library 1.1.1
48867 * Copyright(c) 2006-2007, Ext JS, LLC.
48869 * Originally Released Under LGPL - original licence link has changed is not relivant.
48872 * <script type="text/javascript">
48875 * @class Roo.form.DisplayField
48876 * @extends Roo.form.Field
48877 * A generic Field to display non-editable data.
48878 * @cfg {Boolean} closable (true|false) default false
48880 * Creates a new Display Field item.
48881 * @param {Object} config Configuration options
48883 Roo.form.DisplayField = function(config){
48884 Roo.form.DisplayField.superclass.constructor.call(this, config);
48889 * Fires after the click the close btn
48890 * @param {Roo.form.DisplayField} this
48896 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48897 inputType: 'hidden',
48903 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48905 focusClass : undefined,
48907 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48909 fieldClass: 'x-form-field',
48912 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48914 valueRenderer: undefined,
48918 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48919 * {tag: "input", type: "checkbox", autocomplete: "off"})
48922 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48926 onResize : function(){
48927 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48931 initEvents : function(){
48932 // Roo.form.Checkbox.superclass.initEvents.call(this);
48933 // has no events...
48936 this.closeEl.on('click', this.onClose, this);
48942 getResizeEl : function(){
48946 getPositionEl : function(){
48951 onRender : function(ct, position){
48953 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48954 //if(this.inputValue !== undefined){
48955 this.wrap = this.el.wrap();
48957 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48960 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48963 if (this.bodyStyle) {
48964 this.viewEl.applyStyles(this.bodyStyle);
48966 //this.viewEl.setStyle('padding', '2px');
48968 this.setValue(this.value);
48973 initValue : Roo.emptyFn,
48978 onClick : function(){
48983 * Sets the checked state of the checkbox.
48984 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48986 setValue : function(v){
48988 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
48989 // this might be called before we have a dom element..
48990 if (!this.viewEl) {
48993 this.viewEl.dom.innerHTML = html;
48994 Roo.form.DisplayField.superclass.setValue.call(this, v);
48998 onClose : function(e)
49000 e.preventDefault();
49002 this.fireEvent('close', this);
49011 * @class Roo.form.DayPicker
49012 * @extends Roo.form.Field
49013 * A Day picker show [M] [T] [W] ....
49015 * Creates a new Day Picker
49016 * @param {Object} config Configuration options
49018 Roo.form.DayPicker= function(config){
49019 Roo.form.DayPicker.superclass.constructor.call(this, config);
49023 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49025 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49027 focusClass : undefined,
49029 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49031 fieldClass: "x-form-field",
49034 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49035 * {tag: "input", type: "checkbox", autocomplete: "off"})
49037 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49040 actionMode : 'viewEl',
49044 inputType : 'hidden',
49047 inputElement: false, // real input element?
49048 basedOn: false, // ????
49050 isFormField: true, // not sure where this is needed!!!!
49052 onResize : function(){
49053 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49054 if(!this.boxLabel){
49055 this.el.alignTo(this.wrap, 'c-c');
49059 initEvents : function(){
49060 Roo.form.Checkbox.superclass.initEvents.call(this);
49061 this.el.on("click", this.onClick, this);
49062 this.el.on("change", this.onClick, this);
49066 getResizeEl : function(){
49070 getPositionEl : function(){
49076 onRender : function(ct, position){
49077 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49079 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49081 var r1 = '<table><tr>';
49082 var r2 = '<tr class="x-form-daypick-icons">';
49083 for (var i=0; i < 7; i++) {
49084 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49085 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49088 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49089 viewEl.select('img').on('click', this.onClick, this);
49090 this.viewEl = viewEl;
49093 // this will not work on Chrome!!!
49094 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49095 this.el.on('propertychange', this.setFromHidden, this); //ie
49103 initValue : Roo.emptyFn,
49106 * Returns the checked state of the checkbox.
49107 * @return {Boolean} True if checked, else false
49109 getValue : function(){
49110 return this.el.dom.value;
49115 onClick : function(e){
49116 //this.setChecked(!this.checked);
49117 Roo.get(e.target).toggleClass('x-menu-item-checked');
49118 this.refreshValue();
49119 //if(this.el.dom.checked != this.checked){
49120 // this.setValue(this.el.dom.checked);
49125 refreshValue : function()
49128 this.viewEl.select('img',true).each(function(e,i,n) {
49129 val += e.is(".x-menu-item-checked") ? String(n) : '';
49131 this.setValue(val, true);
49135 * Sets the checked state of the checkbox.
49136 * On is always based on a string comparison between inputValue and the param.
49137 * @param {Boolean/String} value - the value to set
49138 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49140 setValue : function(v,suppressEvent){
49141 if (!this.el.dom) {
49144 var old = this.el.dom.value ;
49145 this.el.dom.value = v;
49146 if (suppressEvent) {
49150 // update display..
49151 this.viewEl.select('img',true).each(function(e,i,n) {
49153 var on = e.is(".x-menu-item-checked");
49154 var newv = v.indexOf(String(n)) > -1;
49156 e.toggleClass('x-menu-item-checked');
49162 this.fireEvent('change', this, v, old);
49167 // handle setting of hidden value by some other method!!?!?
49168 setFromHidden: function()
49173 //console.log("SET FROM HIDDEN");
49174 //alert('setFrom hidden');
49175 this.setValue(this.el.dom.value);
49178 onDestroy : function()
49181 Roo.get(this.viewEl).remove();
49184 Roo.form.DayPicker.superclass.onDestroy.call(this);
49188 * RooJS Library 1.1.1
49189 * Copyright(c) 2008-2011 Alan Knowles
49196 * @class Roo.form.ComboCheck
49197 * @extends Roo.form.ComboBox
49198 * A combobox for multiple select items.
49200 * FIXME - could do with a reset button..
49203 * Create a new ComboCheck
49204 * @param {Object} config Configuration options
49206 Roo.form.ComboCheck = function(config){
49207 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49208 // should verify some data...
49210 // hiddenName = required..
49211 // displayField = required
49212 // valudField == required
49213 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49215 Roo.each(req, function(e) {
49216 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49217 throw "Roo.form.ComboCheck : missing value for: " + e;
49224 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49229 selectedClass: 'x-menu-item-checked',
49232 onRender : function(ct, position){
49238 var cls = 'x-combo-list';
49241 this.tpl = new Roo.Template({
49242 html : '<div class="'+cls+'-item x-menu-check-item">' +
49243 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49244 '<span>{' + this.displayField + '}</span>' +
49251 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49252 this.view.singleSelect = false;
49253 this.view.multiSelect = true;
49254 this.view.toggleSelect = true;
49255 this.pageTb.add(new Roo.Toolbar.Fill(), {
49258 handler: function()
49265 onViewOver : function(e, t){
49271 onViewClick : function(doFocus,index){
49275 select: function () {
49276 //Roo.log("SELECT CALLED");
49279 selectByValue : function(xv, scrollIntoView){
49280 var ar = this.getValueArray();
49283 Roo.each(ar, function(v) {
49284 if(v === undefined || v === null){
49287 var r = this.findRecord(this.valueField, v);
49289 sels.push(this.store.indexOf(r))
49293 this.view.select(sels);
49299 onSelect : function(record, index){
49300 // Roo.log("onselect Called");
49301 // this is only called by the clear button now..
49302 this.view.clearSelections();
49303 this.setValue('[]');
49304 if (this.value != this.valueBefore) {
49305 this.fireEvent('change', this, this.value, this.valueBefore);
49306 this.valueBefore = this.value;
49309 getValueArray : function()
49314 //Roo.log(this.value);
49315 if (typeof(this.value) == 'undefined') {
49318 var ar = Roo.decode(this.value);
49319 return ar instanceof Array ? ar : []; //?? valid?
49322 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49327 expand : function ()
49330 Roo.form.ComboCheck.superclass.expand.call(this);
49331 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49332 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49337 collapse : function(){
49338 Roo.form.ComboCheck.superclass.collapse.call(this);
49339 var sl = this.view.getSelectedIndexes();
49340 var st = this.store;
49344 Roo.each(sl, function(i) {
49346 nv.push(r.get(this.valueField));
49348 this.setValue(Roo.encode(nv));
49349 if (this.value != this.valueBefore) {
49351 this.fireEvent('change', this, this.value, this.valueBefore);
49352 this.valueBefore = this.value;
49357 setValue : function(v){
49361 var vals = this.getValueArray();
49363 Roo.each(vals, function(k) {
49364 var r = this.findRecord(this.valueField, k);
49366 tv.push(r.data[this.displayField]);
49367 }else if(this.valueNotFoundText !== undefined){
49368 tv.push( this.valueNotFoundText );
49373 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49374 this.hiddenField.value = v;
49380 * Ext JS Library 1.1.1
49381 * Copyright(c) 2006-2007, Ext JS, LLC.
49383 * Originally Released Under LGPL - original licence link has changed is not relivant.
49386 * <script type="text/javascript">
49390 * @class Roo.form.Signature
49391 * @extends Roo.form.Field
49395 * @param {Object} config Configuration options
49398 Roo.form.Signature = function(config){
49399 Roo.form.Signature.superclass.constructor.call(this, config);
49401 this.addEvents({// not in used??
49404 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49405 * @param {Roo.form.Signature} combo This combo box
49410 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49411 * @param {Roo.form.ComboBox} combo This combo box
49412 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49418 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49420 * @cfg {Object} labels Label to use when rendering a form.
49424 * confirm : "Confirm"
49429 confirm : "Confirm"
49432 * @cfg {Number} width The signature panel width (defaults to 300)
49436 * @cfg {Number} height The signature panel height (defaults to 100)
49440 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49442 allowBlank : false,
49445 // {Object} signPanel The signature SVG panel element (defaults to {})
49447 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49448 isMouseDown : false,
49449 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49450 isConfirmed : false,
49451 // {String} signatureTmp SVG mapping string (defaults to empty string)
49455 defaultAutoCreate : { // modified by initCompnoent..
49461 onRender : function(ct, position){
49463 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49465 this.wrap = this.el.wrap({
49466 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49469 this.createToolbar(this);
49470 this.signPanel = this.wrap.createChild({
49472 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49476 this.svgID = Roo.id();
49477 this.svgEl = this.signPanel.createChild({
49478 xmlns : 'http://www.w3.org/2000/svg',
49480 id : this.svgID + "-svg",
49482 height: this.height,
49483 viewBox: '0 0 '+this.width+' '+this.height,
49487 id: this.svgID + "-svg-r",
49489 height: this.height,
49494 id: this.svgID + "-svg-l",
49496 y1: (this.height*0.8), // start set the line in 80% of height
49497 x2: this.width, // end
49498 y2: (this.height*0.8), // end set the line in 80% of height
49500 'stroke-width': "1",
49501 'stroke-dasharray': "3",
49502 'shape-rendering': "crispEdges",
49503 'pointer-events': "none"
49507 id: this.svgID + "-svg-p",
49509 'stroke-width': "3",
49511 'pointer-events': 'none'
49516 this.svgBox = this.svgEl.dom.getScreenCTM();
49518 createSVG : function(){
49519 var svg = this.signPanel;
49520 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49523 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49524 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49525 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49526 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49527 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49528 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49529 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49532 isTouchEvent : function(e){
49533 return e.type.match(/^touch/);
49535 getCoords : function (e) {
49536 var pt = this.svgEl.dom.createSVGPoint();
49539 if (this.isTouchEvent(e)) {
49540 pt.x = e.targetTouches[0].clientX;
49541 pt.y = e.targetTouches[0].clientY;
49543 var a = this.svgEl.dom.getScreenCTM();
49544 var b = a.inverse();
49545 var mx = pt.matrixTransform(b);
49546 return mx.x + ',' + mx.y;
49548 //mouse event headler
49549 down : function (e) {
49550 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49551 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49553 this.isMouseDown = true;
49555 e.preventDefault();
49557 move : function (e) {
49558 if (this.isMouseDown) {
49559 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49560 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49563 e.preventDefault();
49565 up : function (e) {
49566 this.isMouseDown = false;
49567 var sp = this.signatureTmp.split(' ');
49570 if(!sp[sp.length-2].match(/^L/)){
49574 this.signatureTmp = sp.join(" ");
49577 if(this.getValue() != this.signatureTmp){
49578 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49579 this.isConfirmed = false;
49581 e.preventDefault();
49585 * Protected method that will not generally be called directly. It
49586 * is called when the editor creates its toolbar. Override this method if you need to
49587 * add custom toolbar buttons.
49588 * @param {HtmlEditor} editor
49590 createToolbar : function(editor){
49591 function btn(id, toggle, handler){
49592 var xid = fid + '-'+ id ;
49596 cls : 'x-btn-icon x-edit-'+id,
49597 enableToggle:toggle !== false,
49598 scope: editor, // was editor...
49599 handler:handler||editor.relayBtnCmd,
49600 clickEvent:'mousedown',
49601 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49607 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49611 cls : ' x-signature-btn x-signature-'+id,
49612 scope: editor, // was editor...
49613 handler: this.reset,
49614 clickEvent:'mousedown',
49615 text: this.labels.clear
49622 cls : ' x-signature-btn x-signature-'+id,
49623 scope: editor, // was editor...
49624 handler: this.confirmHandler,
49625 clickEvent:'mousedown',
49626 text: this.labels.confirm
49633 * when user is clicked confirm then show this image.....
49635 * @return {String} Image Data URI
49637 getImageDataURI : function(){
49638 var svg = this.svgEl.dom.parentNode.innerHTML;
49639 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49644 * @return {Boolean} this.isConfirmed
49646 getConfirmed : function(){
49647 return this.isConfirmed;
49651 * @return {Number} this.width
49653 getWidth : function(){
49658 * @return {Number} this.height
49660 getHeight : function(){
49661 return this.height;
49664 getSignature : function(){
49665 return this.signatureTmp;
49668 reset : function(){
49669 this.signatureTmp = '';
49670 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49671 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49672 this.isConfirmed = false;
49673 Roo.form.Signature.superclass.reset.call(this);
49675 setSignature : function(s){
49676 this.signatureTmp = s;
49677 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49678 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49680 this.isConfirmed = false;
49681 Roo.form.Signature.superclass.reset.call(this);
49684 // Roo.log(this.signPanel.dom.contentWindow.up())
49687 setConfirmed : function(){
49691 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49694 confirmHandler : function(){
49695 if(!this.getSignature()){
49699 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49700 this.setValue(this.getSignature());
49701 this.isConfirmed = true;
49703 this.fireEvent('confirm', this);
49706 // Subclasses should provide the validation implementation by overriding this
49707 validateValue : function(value){
49708 if(this.allowBlank){
49712 if(this.isConfirmed){
49719 * Ext JS Library 1.1.1
49720 * Copyright(c) 2006-2007, Ext JS, LLC.
49722 * Originally Released Under LGPL - original licence link has changed is not relivant.
49725 * <script type="text/javascript">
49730 * @class Roo.form.ComboBox
49731 * @extends Roo.form.TriggerField
49732 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49734 * Create a new ComboBox.
49735 * @param {Object} config Configuration options
49737 Roo.form.Select = function(config){
49738 Roo.form.Select.superclass.constructor.call(this, config);
49742 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49744 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49747 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49748 * rendering into an Roo.Editor, defaults to false)
49751 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49752 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49755 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49758 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49759 * the dropdown list (defaults to undefined, with no header element)
49763 * @cfg {String/Roo.Template} tpl The template to use to render the output
49767 defaultAutoCreate : {tag: "select" },
49769 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49771 listWidth: undefined,
49773 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49774 * mode = 'remote' or 'text' if mode = 'local')
49776 displayField: undefined,
49778 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49779 * mode = 'remote' or 'value' if mode = 'local').
49780 * Note: use of a valueField requires the user make a selection
49781 * in order for a value to be mapped.
49783 valueField: undefined,
49787 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49788 * field's data value (defaults to the underlying DOM element's name)
49790 hiddenName: undefined,
49792 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49796 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49798 selectedClass: 'x-combo-selected',
49800 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49801 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49802 * which displays a downward arrow icon).
49804 triggerClass : 'x-form-arrow-trigger',
49806 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49810 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49811 * anchor positions (defaults to 'tl-bl')
49813 listAlign: 'tl-bl?',
49815 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49819 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49820 * query specified by the allQuery config option (defaults to 'query')
49822 triggerAction: 'query',
49824 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49825 * (defaults to 4, does not apply if editable = false)
49829 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49830 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49834 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49835 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49839 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49840 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49844 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49845 * when editable = true (defaults to false)
49847 selectOnFocus:false,
49849 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49851 queryParam: 'query',
49853 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49854 * when mode = 'remote' (defaults to 'Loading...')
49856 loadingText: 'Loading...',
49858 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49862 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49866 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49867 * traditional select (defaults to true)
49871 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49875 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49879 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49880 * listWidth has a higher value)
49884 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49885 * allow the user to set arbitrary text into the field (defaults to false)
49887 forceSelection:false,
49889 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49890 * if typeAhead = true (defaults to 250)
49892 typeAheadDelay : 250,
49894 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49895 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49897 valueNotFoundText : undefined,
49900 * @cfg {String} defaultValue The value displayed after loading the store.
49905 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49907 blockFocus : false,
49910 * @cfg {Boolean} disableClear Disable showing of clear button.
49912 disableClear : false,
49914 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49916 alwaysQuery : false,
49922 // element that contains real text value.. (when hidden is used..)
49925 onRender : function(ct, position){
49926 Roo.form.Field.prototype.onRender.call(this, ct, position);
49929 this.store.on('beforeload', this.onBeforeLoad, this);
49930 this.store.on('load', this.onLoad, this);
49931 this.store.on('loadexception', this.onLoadException, this);
49932 this.store.load({});
49940 initEvents : function(){
49941 //Roo.form.ComboBox.superclass.initEvents.call(this);
49945 onDestroy : function(){
49948 this.store.un('beforeload', this.onBeforeLoad, this);
49949 this.store.un('load', this.onLoad, this);
49950 this.store.un('loadexception', this.onLoadException, this);
49952 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49956 fireKey : function(e){
49957 if(e.isNavKeyPress() && !this.list.isVisible()){
49958 this.fireEvent("specialkey", this, e);
49963 onResize: function(w, h){
49971 * Allow or prevent the user from directly editing the field text. If false is passed,
49972 * the user will only be able to select from the items defined in the dropdown list. This method
49973 * is the runtime equivalent of setting the 'editable' config option at config time.
49974 * @param {Boolean} value True to allow the user to directly edit the field text
49976 setEditable : function(value){
49981 onBeforeLoad : function(){
49983 Roo.log("Select before load");
49986 this.innerList.update(this.loadingText ?
49987 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49988 //this.restrictHeight();
49989 this.selectedIndex = -1;
49993 onLoad : function(){
49996 var dom = this.el.dom;
49997 dom.innerHTML = '';
49998 var od = dom.ownerDocument;
50000 if (this.emptyText) {
50001 var op = od.createElement('option');
50002 op.setAttribute('value', '');
50003 op.innerHTML = String.format('{0}', this.emptyText);
50004 dom.appendChild(op);
50006 if(this.store.getCount() > 0){
50008 var vf = this.valueField;
50009 var df = this.displayField;
50010 this.store.data.each(function(r) {
50011 // which colmsn to use... testing - cdoe / title..
50012 var op = od.createElement('option');
50013 op.setAttribute('value', r.data[vf]);
50014 op.innerHTML = String.format('{0}', r.data[df]);
50015 dom.appendChild(op);
50017 if (typeof(this.defaultValue != 'undefined')) {
50018 this.setValue(this.defaultValue);
50023 //this.onEmptyResults();
50028 onLoadException : function()
50030 dom.innerHTML = '';
50032 Roo.log("Select on load exception");
50036 Roo.log(this.store.reader.jsonData);
50037 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50038 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50044 onTypeAhead : function(){
50049 onSelect : function(record, index){
50050 Roo.log('on select?');
50052 if(this.fireEvent('beforeselect', this, record, index) !== false){
50053 this.setFromData(index > -1 ? record.data : false);
50055 this.fireEvent('select', this, record, index);
50060 * Returns the currently selected field value or empty string if no value is set.
50061 * @return {String} value The selected value
50063 getValue : function(){
50064 var dom = this.el.dom;
50065 this.value = dom.options[dom.selectedIndex].value;
50071 * Clears any text/value currently set in the field
50073 clearValue : function(){
50075 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50080 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50081 * will be displayed in the field. If the value does not match the data value of an existing item,
50082 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50083 * Otherwise the field will be blank (although the value will still be set).
50084 * @param {String} value The value to match
50086 setValue : function(v){
50087 var d = this.el.dom;
50088 for (var i =0; i < d.options.length;i++) {
50089 if (v == d.options[i].value) {
50090 d.selectedIndex = i;
50098 * @property {Object} the last set data for the element
50103 * Sets the value of the field based on a object which is related to the record format for the store.
50104 * @param {Object} value the value to set as. or false on reset?
50106 setFromData : function(o){
50107 Roo.log('setfrom data?');
50113 reset : function(){
50117 findRecord : function(prop, value){
50122 if(this.store.getCount() > 0){
50123 this.store.each(function(r){
50124 if(r.data[prop] == value){
50134 getName: function()
50136 // returns hidden if it's set..
50137 if (!this.rendered) {return ''};
50138 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50146 onEmptyResults : function(){
50147 Roo.log('empty results');
50152 * Returns true if the dropdown list is expanded, else false.
50154 isExpanded : function(){
50159 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50160 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50161 * @param {String} value The data value of the item to select
50162 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50163 * selected item if it is not currently in view (defaults to true)
50164 * @return {Boolean} True if the value matched an item in the list, else false
50166 selectByValue : function(v, scrollIntoView){
50167 Roo.log('select By Value');
50170 if(v !== undefined && v !== null){
50171 var r = this.findRecord(this.valueField || this.displayField, v);
50173 this.select(this.store.indexOf(r), scrollIntoView);
50181 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50182 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50183 * @param {Number} index The zero-based index of the list item to select
50184 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50185 * selected item if it is not currently in view (defaults to true)
50187 select : function(index, scrollIntoView){
50188 Roo.log('select ');
50191 this.selectedIndex = index;
50192 this.view.select(index);
50193 if(scrollIntoView !== false){
50194 var el = this.view.getNode(index);
50196 this.innerList.scrollChildIntoView(el, false);
50204 validateBlur : function(){
50211 initQuery : function(){
50212 this.doQuery(this.getRawValue());
50216 doForce : function(){
50217 if(this.el.dom.value.length > 0){
50218 this.el.dom.value =
50219 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50225 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50226 * query allowing the query action to be canceled if needed.
50227 * @param {String} query The SQL query to execute
50228 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50229 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50230 * saved in the current store (defaults to false)
50232 doQuery : function(q, forceAll){
50234 Roo.log('doQuery?');
50235 if(q === undefined || q === null){
50240 forceAll: forceAll,
50244 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50248 forceAll = qe.forceAll;
50249 if(forceAll === true || (q.length >= this.minChars)){
50250 if(this.lastQuery != q || this.alwaysQuery){
50251 this.lastQuery = q;
50252 if(this.mode == 'local'){
50253 this.selectedIndex = -1;
50255 this.store.clearFilter();
50257 this.store.filter(this.displayField, q);
50261 this.store.baseParams[this.queryParam] = q;
50263 params: this.getParams(q)
50268 this.selectedIndex = -1;
50275 getParams : function(q){
50277 //p[this.queryParam] = q;
50280 p.limit = this.pageSize;
50286 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50288 collapse : function(){
50293 collapseIf : function(e){
50298 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50300 expand : function(){
50308 * @cfg {Boolean} grow
50312 * @cfg {Number} growMin
50316 * @cfg {Number} growMax
50324 setWidth : function()
50328 getResizeEl : function(){
50331 });//<script type="text/javasscript">
50335 * @class Roo.DDView
50336 * A DnD enabled version of Roo.View.
50337 * @param {Element/String} container The Element in which to create the View.
50338 * @param {String} tpl The template string used to create the markup for each element of the View
50339 * @param {Object} config The configuration properties. These include all the config options of
50340 * {@link Roo.View} plus some specific to this class.<br>
50342 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50343 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50345 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50346 .x-view-drag-insert-above {
50347 border-top:1px dotted #3366cc;
50349 .x-view-drag-insert-below {
50350 border-bottom:1px dotted #3366cc;
50356 Roo.DDView = function(container, tpl, config) {
50357 Roo.DDView.superclass.constructor.apply(this, arguments);
50358 this.getEl().setStyle("outline", "0px none");
50359 this.getEl().unselectable();
50360 if (this.dragGroup) {
50361 this.setDraggable(this.dragGroup.split(","));
50363 if (this.dropGroup) {
50364 this.setDroppable(this.dropGroup.split(","));
50366 if (this.deletable) {
50367 this.setDeletable();
50369 this.isDirtyFlag = false;
50375 Roo.extend(Roo.DDView, Roo.View, {
50376 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50377 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50378 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50379 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50383 reset: Roo.emptyFn,
50385 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50387 validate: function() {
50391 destroy: function() {
50392 this.purgeListeners();
50393 this.getEl.removeAllListeners();
50394 this.getEl().remove();
50395 if (this.dragZone) {
50396 if (this.dragZone.destroy) {
50397 this.dragZone.destroy();
50400 if (this.dropZone) {
50401 if (this.dropZone.destroy) {
50402 this.dropZone.destroy();
50407 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50408 getName: function() {
50412 /** Loads the View from a JSON string representing the Records to put into the Store. */
50413 setValue: function(v) {
50415 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50418 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50419 this.store.proxy = new Roo.data.MemoryProxy(data);
50423 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50424 getValue: function() {
50426 this.store.each(function(rec) {
50427 result += rec.id + ',';
50429 return result.substr(0, result.length - 1) + ')';
50432 getIds: function() {
50433 var i = 0, result = new Array(this.store.getCount());
50434 this.store.each(function(rec) {
50435 result[i++] = rec.id;
50440 isDirty: function() {
50441 return this.isDirtyFlag;
50445 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50446 * whole Element becomes the target, and this causes the drop gesture to append.
50448 getTargetFromEvent : function(e) {
50449 var target = e.getTarget();
50450 while ((target !== null) && (target.parentNode != this.el.dom)) {
50451 target = target.parentNode;
50454 target = this.el.dom.lastChild || this.el.dom;
50460 * Create the drag data which consists of an object which has the property "ddel" as
50461 * the drag proxy element.
50463 getDragData : function(e) {
50464 var target = this.findItemFromChild(e.getTarget());
50466 this.handleSelection(e);
50467 var selNodes = this.getSelectedNodes();
50470 copy: this.copy || (this.allowCopy && e.ctrlKey),
50474 var selectedIndices = this.getSelectedIndexes();
50475 for (var i = 0; i < selectedIndices.length; i++) {
50476 dragData.records.push(this.store.getAt(selectedIndices[i]));
50478 if (selNodes.length == 1) {
50479 dragData.ddel = target.cloneNode(true); // the div element
50481 var div = document.createElement('div'); // create the multi element drag "ghost"
50482 div.className = 'multi-proxy';
50483 for (var i = 0, len = selNodes.length; i < len; i++) {
50484 div.appendChild(selNodes[i].cloneNode(true));
50486 dragData.ddel = div;
50488 //console.log(dragData)
50489 //console.log(dragData.ddel.innerHTML)
50492 //console.log('nodragData')
50496 /** Specify to which ddGroup items in this DDView may be dragged. */
50497 setDraggable: function(ddGroup) {
50498 if (ddGroup instanceof Array) {
50499 Roo.each(ddGroup, this.setDraggable, this);
50502 if (this.dragZone) {
50503 this.dragZone.addToGroup(ddGroup);
50505 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50506 containerScroll: true,
50510 // Draggability implies selection. DragZone's mousedown selects the element.
50511 if (!this.multiSelect) { this.singleSelect = true; }
50513 // Wire the DragZone's handlers up to methods in *this*
50514 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50518 /** Specify from which ddGroup this DDView accepts drops. */
50519 setDroppable: function(ddGroup) {
50520 if (ddGroup instanceof Array) {
50521 Roo.each(ddGroup, this.setDroppable, this);
50524 if (this.dropZone) {
50525 this.dropZone.addToGroup(ddGroup);
50527 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50528 containerScroll: true,
50532 // Wire the DropZone's handlers up to methods in *this*
50533 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50534 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50535 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50536 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50537 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50541 /** Decide whether to drop above or below a View node. */
50542 getDropPoint : function(e, n, dd){
50543 if (n == this.el.dom) { return "above"; }
50544 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50545 var c = t + (b - t) / 2;
50546 var y = Roo.lib.Event.getPageY(e);
50554 onNodeEnter : function(n, dd, e, data){
50558 onNodeOver : function(n, dd, e, data){
50559 var pt = this.getDropPoint(e, n, dd);
50560 // set the insert point style on the target node
50561 var dragElClass = this.dropNotAllowed;
50564 if (pt == "above"){
50565 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50566 targetElClass = "x-view-drag-insert-above";
50568 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50569 targetElClass = "x-view-drag-insert-below";
50571 if (this.lastInsertClass != targetElClass){
50572 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50573 this.lastInsertClass = targetElClass;
50576 return dragElClass;
50579 onNodeOut : function(n, dd, e, data){
50580 this.removeDropIndicators(n);
50583 onNodeDrop : function(n, dd, e, data){
50584 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50587 var pt = this.getDropPoint(e, n, dd);
50588 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50589 if (pt == "below") { insertAt++; }
50590 for (var i = 0; i < data.records.length; i++) {
50591 var r = data.records[i];
50592 var dup = this.store.getById(r.id);
50593 if (dup && (dd != this.dragZone)) {
50594 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50597 this.store.insert(insertAt++, r.copy());
50599 data.source.isDirtyFlag = true;
50601 this.store.insert(insertAt++, r);
50603 this.isDirtyFlag = true;
50606 this.dragZone.cachedTarget = null;
50610 removeDropIndicators : function(n){
50612 Roo.fly(n).removeClass([
50613 "x-view-drag-insert-above",
50614 "x-view-drag-insert-below"]);
50615 this.lastInsertClass = "_noclass";
50620 * Utility method. Add a delete option to the DDView's context menu.
50621 * @param {String} imageUrl The URL of the "delete" icon image.
50623 setDeletable: function(imageUrl) {
50624 if (!this.singleSelect && !this.multiSelect) {
50625 this.singleSelect = true;
50627 var c = this.getContextMenu();
50628 this.contextMenu.on("itemclick", function(item) {
50631 this.remove(this.getSelectedIndexes());
50635 this.contextMenu.add({
50642 /** Return the context menu for this DDView. */
50643 getContextMenu: function() {
50644 if (!this.contextMenu) {
50645 // Create the View's context menu
50646 this.contextMenu = new Roo.menu.Menu({
50647 id: this.id + "-contextmenu"
50649 this.el.on("contextmenu", this.showContextMenu, this);
50651 return this.contextMenu;
50654 disableContextMenu: function() {
50655 if (this.contextMenu) {
50656 this.el.un("contextmenu", this.showContextMenu, this);
50660 showContextMenu: function(e, item) {
50661 item = this.findItemFromChild(e.getTarget());
50664 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50665 this.contextMenu.showAt(e.getXY());
50670 * Remove {@link Roo.data.Record}s at the specified indices.
50671 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50673 remove: function(selectedIndices) {
50674 selectedIndices = [].concat(selectedIndices);
50675 for (var i = 0; i < selectedIndices.length; i++) {
50676 var rec = this.store.getAt(selectedIndices[i]);
50677 this.store.remove(rec);
50682 * Double click fires the event, but also, if this is draggable, and there is only one other
50683 * related DropZone, it transfers the selected node.
50685 onDblClick : function(e){
50686 var item = this.findItemFromChild(e.getTarget());
50688 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50691 if (this.dragGroup) {
50692 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50693 while (targets.indexOf(this.dropZone) > -1) {
50694 targets.remove(this.dropZone);
50696 if (targets.length == 1) {
50697 this.dragZone.cachedTarget = null;
50698 var el = Roo.get(targets[0].getEl());
50699 var box = el.getBox(true);
50700 targets[0].onNodeDrop(el.dom, {
50702 xy: [box.x, box.y + box.height - 1]
50703 }, null, this.getDragData(e));
50709 handleSelection: function(e) {
50710 this.dragZone.cachedTarget = null;
50711 var item = this.findItemFromChild(e.getTarget());
50713 this.clearSelections(true);
50716 if (item && (this.multiSelect || this.singleSelect)){
50717 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50718 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50719 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50720 this.unselect(item);
50722 this.select(item, this.multiSelect && e.ctrlKey);
50723 this.lastSelection = item;
50728 onItemClick : function(item, index, e){
50729 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50735 unselect : function(nodeInfo, suppressEvent){
50736 var node = this.getNode(nodeInfo);
50737 if(node && this.isSelected(node)){
50738 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50739 Roo.fly(node).removeClass(this.selectedClass);
50740 this.selections.remove(node);
50741 if(!suppressEvent){
50742 this.fireEvent("selectionchange", this, this.selections);
50750 * Ext JS Library 1.1.1
50751 * Copyright(c) 2006-2007, Ext JS, LLC.
50753 * Originally Released Under LGPL - original licence link has changed is not relivant.
50756 * <script type="text/javascript">
50760 * @class Roo.LayoutManager
50761 * @extends Roo.util.Observable
50762 * Base class for layout managers.
50764 Roo.LayoutManager = function(container, config){
50765 Roo.LayoutManager.superclass.constructor.call(this);
50766 this.el = Roo.get(container);
50767 // ie scrollbar fix
50768 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50769 document.body.scroll = "no";
50770 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50771 this.el.position('relative');
50773 this.id = this.el.id;
50774 this.el.addClass("x-layout-container");
50775 /** false to disable window resize monitoring @type Boolean */
50776 this.monitorWindowResize = true;
50781 * Fires when a layout is performed.
50782 * @param {Roo.LayoutManager} this
50786 * @event regionresized
50787 * Fires when the user resizes a region.
50788 * @param {Roo.LayoutRegion} region The resized region
50789 * @param {Number} newSize The new size (width for east/west, height for north/south)
50791 "regionresized" : true,
50793 * @event regioncollapsed
50794 * Fires when a region is collapsed.
50795 * @param {Roo.LayoutRegion} region The collapsed region
50797 "regioncollapsed" : true,
50799 * @event regionexpanded
50800 * Fires when a region is expanded.
50801 * @param {Roo.LayoutRegion} region The expanded region
50803 "regionexpanded" : true
50805 this.updating = false;
50806 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50809 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50811 * Returns true if this layout is currently being updated
50812 * @return {Boolean}
50814 isUpdating : function(){
50815 return this.updating;
50819 * Suspend the LayoutManager from doing auto-layouts while
50820 * making multiple add or remove calls
50822 beginUpdate : function(){
50823 this.updating = true;
50827 * Restore auto-layouts and optionally disable the manager from performing a layout
50828 * @param {Boolean} noLayout true to disable a layout update
50830 endUpdate : function(noLayout){
50831 this.updating = false;
50837 layout: function(){
50841 onRegionResized : function(region, newSize){
50842 this.fireEvent("regionresized", region, newSize);
50846 onRegionCollapsed : function(region){
50847 this.fireEvent("regioncollapsed", region);
50850 onRegionExpanded : function(region){
50851 this.fireEvent("regionexpanded", region);
50855 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50856 * performs box-model adjustments.
50857 * @return {Object} The size as an object {width: (the width), height: (the height)}
50859 getViewSize : function(){
50861 if(this.el.dom != document.body){
50862 size = this.el.getSize();
50864 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50866 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50867 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50872 * Returns the Element this layout is bound to.
50873 * @return {Roo.Element}
50875 getEl : function(){
50880 * Returns the specified region.
50881 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50882 * @return {Roo.LayoutRegion}
50884 getRegion : function(target){
50885 return this.regions[target.toLowerCase()];
50888 onWindowResize : function(){
50889 if(this.monitorWindowResize){
50895 * Ext JS Library 1.1.1
50896 * Copyright(c) 2006-2007, Ext JS, LLC.
50898 * Originally Released Under LGPL - original licence link has changed is not relivant.
50901 * <script type="text/javascript">
50904 * @class Roo.BorderLayout
50905 * @extends Roo.LayoutManager
50906 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50907 * please see: <br><br>
50908 * <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>
50909 * <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>
50912 var layout = new Roo.BorderLayout(document.body, {
50946 preferredTabWidth: 150
50951 var CP = Roo.ContentPanel;
50953 layout.beginUpdate();
50954 layout.add("north", new CP("north", "North"));
50955 layout.add("south", new CP("south", {title: "South", closable: true}));
50956 layout.add("west", new CP("west", {title: "West"}));
50957 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50958 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50959 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50960 layout.getRegion("center").showPanel("center1");
50961 layout.endUpdate();
50964 <b>The container the layout is rendered into can be either the body element or any other element.
50965 If it is not the body element, the container needs to either be an absolute positioned element,
50966 or you will need to add "position:relative" to the css of the container. You will also need to specify
50967 the container size if it is not the body element.</b>
50970 * Create a new BorderLayout
50971 * @param {String/HTMLElement/Element} container The container this layout is bound to
50972 * @param {Object} config Configuration options
50974 Roo.BorderLayout = function(container, config){
50975 config = config || {};
50976 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50977 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50978 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50979 var target = this.factory.validRegions[i];
50980 if(config[target]){
50981 this.addRegion(target, config[target]);
50986 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50988 * Creates and adds a new region if it doesn't already exist.
50989 * @param {String} target The target region key (north, south, east, west or center).
50990 * @param {Object} config The regions config object
50991 * @return {BorderLayoutRegion} The new region
50993 addRegion : function(target, config){
50994 if(!this.regions[target]){
50995 var r = this.factory.create(target, this, config);
50996 this.bindRegion(target, r);
50998 return this.regions[target];
51002 bindRegion : function(name, r){
51003 this.regions[name] = r;
51004 r.on("visibilitychange", this.layout, this);
51005 r.on("paneladded", this.layout, this);
51006 r.on("panelremoved", this.layout, this);
51007 r.on("invalidated", this.layout, this);
51008 r.on("resized", this.onRegionResized, this);
51009 r.on("collapsed", this.onRegionCollapsed, this);
51010 r.on("expanded", this.onRegionExpanded, this);
51014 * Performs a layout update.
51016 layout : function(){
51017 if(this.updating) {
51020 var size = this.getViewSize();
51021 var w = size.width;
51022 var h = size.height;
51027 //var x = 0, y = 0;
51029 var rs = this.regions;
51030 var north = rs["north"];
51031 var south = rs["south"];
51032 var west = rs["west"];
51033 var east = rs["east"];
51034 var center = rs["center"];
51035 //if(this.hideOnLayout){ // not supported anymore
51036 //c.el.setStyle("display", "none");
51038 if(north && north.isVisible()){
51039 var b = north.getBox();
51040 var m = north.getMargins();
51041 b.width = w - (m.left+m.right);
51044 centerY = b.height + b.y + m.bottom;
51045 centerH -= centerY;
51046 north.updateBox(this.safeBox(b));
51048 if(south && south.isVisible()){
51049 var b = south.getBox();
51050 var m = south.getMargins();
51051 b.width = w - (m.left+m.right);
51053 var totalHeight = (b.height + m.top + m.bottom);
51054 b.y = h - totalHeight + m.top;
51055 centerH -= totalHeight;
51056 south.updateBox(this.safeBox(b));
51058 if(west && west.isVisible()){
51059 var b = west.getBox();
51060 var m = west.getMargins();
51061 b.height = centerH - (m.top+m.bottom);
51063 b.y = centerY + m.top;
51064 var totalWidth = (b.width + m.left + m.right);
51065 centerX += totalWidth;
51066 centerW -= totalWidth;
51067 west.updateBox(this.safeBox(b));
51069 if(east && east.isVisible()){
51070 var b = east.getBox();
51071 var m = east.getMargins();
51072 b.height = centerH - (m.top+m.bottom);
51073 var totalWidth = (b.width + m.left + m.right);
51074 b.x = w - totalWidth + m.left;
51075 b.y = centerY + m.top;
51076 centerW -= totalWidth;
51077 east.updateBox(this.safeBox(b));
51080 var m = center.getMargins();
51082 x: centerX + m.left,
51083 y: centerY + m.top,
51084 width: centerW - (m.left+m.right),
51085 height: centerH - (m.top+m.bottom)
51087 //if(this.hideOnLayout){
51088 //center.el.setStyle("display", "block");
51090 center.updateBox(this.safeBox(centerBox));
51093 this.fireEvent("layout", this);
51097 safeBox : function(box){
51098 box.width = Math.max(0, box.width);
51099 box.height = Math.max(0, box.height);
51104 * Adds a ContentPanel (or subclass) to this layout.
51105 * @param {String} target The target region key (north, south, east, west or center).
51106 * @param {Roo.ContentPanel} panel The panel to add
51107 * @return {Roo.ContentPanel} The added panel
51109 add : function(target, panel){
51111 target = target.toLowerCase();
51112 return this.regions[target].add(panel);
51116 * Remove a ContentPanel (or subclass) to this layout.
51117 * @param {String} target The target region key (north, south, east, west or center).
51118 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51119 * @return {Roo.ContentPanel} The removed panel
51121 remove : function(target, panel){
51122 target = target.toLowerCase();
51123 return this.regions[target].remove(panel);
51127 * Searches all regions for a panel with the specified id
51128 * @param {String} panelId
51129 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51131 findPanel : function(panelId){
51132 var rs = this.regions;
51133 for(var target in rs){
51134 if(typeof rs[target] != "function"){
51135 var p = rs[target].getPanel(panelId);
51145 * Searches all regions for a panel with the specified id and activates (shows) it.
51146 * @param {String/ContentPanel} panelId The panels id or the panel itself
51147 * @return {Roo.ContentPanel} The shown panel or null
51149 showPanel : function(panelId) {
51150 var rs = this.regions;
51151 for(var target in rs){
51152 var r = rs[target];
51153 if(typeof r != "function"){
51154 if(r.hasPanel(panelId)){
51155 return r.showPanel(panelId);
51163 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51164 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51166 restoreState : function(provider){
51168 provider = Roo.state.Manager;
51170 var sm = new Roo.LayoutStateManager();
51171 sm.init(this, provider);
51175 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51176 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51177 * a valid ContentPanel config object. Example:
51179 // Create the main layout
51180 var layout = new Roo.BorderLayout('main-ct', {
51191 // Create and add multiple ContentPanels at once via configs
51194 id: 'source-files',
51196 title:'Ext Source Files',
51209 * @param {Object} regions An object containing ContentPanel configs by region name
51211 batchAdd : function(regions){
51212 this.beginUpdate();
51213 for(var rname in regions){
51214 var lr = this.regions[rname];
51216 this.addTypedPanels(lr, regions[rname]);
51223 addTypedPanels : function(lr, ps){
51224 if(typeof ps == 'string'){
51225 lr.add(new Roo.ContentPanel(ps));
51227 else if(ps instanceof Array){
51228 for(var i =0, len = ps.length; i < len; i++){
51229 this.addTypedPanels(lr, ps[i]);
51232 else if(!ps.events){ // raw config?
51234 delete ps.el; // prevent conflict
51235 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51237 else { // panel object assumed!
51242 * Adds a xtype elements to the layout.
51246 xtype : 'ContentPanel',
51253 xtype : 'NestedLayoutPanel',
51259 items : [ ... list of content panels or nested layout panels.. ]
51263 * @param {Object} cfg Xtype definition of item to add.
51265 addxtype : function(cfg)
51267 // basically accepts a pannel...
51268 // can accept a layout region..!?!?
51269 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51271 if (!cfg.xtype.match(/Panel$/)) {
51276 if (typeof(cfg.region) == 'undefined') {
51277 Roo.log("Failed to add Panel, region was not set");
51281 var region = cfg.region;
51287 xitems = cfg.items;
51294 case 'ContentPanel': // ContentPanel (el, cfg)
51295 case 'ScrollPanel': // ContentPanel (el, cfg)
51297 if(cfg.autoCreate) {
51298 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51300 var el = this.el.createChild();
51301 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51304 this.add(region, ret);
51308 case 'TreePanel': // our new panel!
51309 cfg.el = this.el.createChild();
51310 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51311 this.add(region, ret);
51314 case 'NestedLayoutPanel':
51315 // create a new Layout (which is a Border Layout...
51316 var el = this.el.createChild();
51317 var clayout = cfg.layout;
51319 clayout.items = clayout.items || [];
51320 // replace this exitems with the clayout ones..
51321 xitems = clayout.items;
51324 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51325 cfg.background = false;
51327 var layout = new Roo.BorderLayout(el, clayout);
51329 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51330 //console.log('adding nested layout panel ' + cfg.toSource());
51331 this.add(region, ret);
51332 nb = {}; /// find first...
51337 // needs grid and region
51339 //var el = this.getRegion(region).el.createChild();
51340 var el = this.el.createChild();
51341 // create the grid first...
51343 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51345 if (region == 'center' && this.active ) {
51346 cfg.background = false;
51348 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51350 this.add(region, ret);
51351 if (cfg.background) {
51352 ret.on('activate', function(gp) {
51353 if (!gp.grid.rendered) {
51368 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51370 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51371 this.add(region, ret);
51374 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51378 // GridPanel (grid, cfg)
51381 this.beginUpdate();
51385 Roo.each(xitems, function(i) {
51386 region = nb && i.region ? i.region : false;
51388 var add = ret.addxtype(i);
51391 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51392 if (!i.background) {
51393 abn[region] = nb[region] ;
51400 // make the last non-background panel active..
51401 //if (nb) { Roo.log(abn); }
51404 for(var r in abn) {
51405 region = this.getRegion(r);
51407 // tried using nb[r], but it does not work..
51409 region.showPanel(abn[r]);
51420 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51421 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51422 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51423 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51426 var CP = Roo.ContentPanel;
51428 var layout = Roo.BorderLayout.create({
51432 panels: [new CP("north", "North")]
51441 panels: [new CP("west", {title: "West"})]
51450 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51459 panels: [new CP("south", {title: "South", closable: true})]
51466 preferredTabWidth: 150,
51468 new CP("center1", {title: "Close Me", closable: true}),
51469 new CP("center2", {title: "Center Panel", closable: false})
51474 layout.getRegion("center").showPanel("center1");
51479 Roo.BorderLayout.create = function(config, targetEl){
51480 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51481 layout.beginUpdate();
51482 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51483 for(var j = 0, jlen = regions.length; j < jlen; j++){
51484 var lr = regions[j];
51485 if(layout.regions[lr] && config[lr].panels){
51486 var r = layout.regions[lr];
51487 var ps = config[lr].panels;
51488 layout.addTypedPanels(r, ps);
51491 layout.endUpdate();
51496 Roo.BorderLayout.RegionFactory = {
51498 validRegions : ["north","south","east","west","center"],
51501 create : function(target, mgr, config){
51502 target = target.toLowerCase();
51503 if(config.lightweight || config.basic){
51504 return new Roo.BasicLayoutRegion(mgr, config, target);
51508 return new Roo.NorthLayoutRegion(mgr, config);
51510 return new Roo.SouthLayoutRegion(mgr, config);
51512 return new Roo.EastLayoutRegion(mgr, config);
51514 return new Roo.WestLayoutRegion(mgr, config);
51516 return new Roo.CenterLayoutRegion(mgr, config);
51518 throw 'Layout region "'+target+'" not supported.';
51522 * Ext JS Library 1.1.1
51523 * Copyright(c) 2006-2007, Ext JS, LLC.
51525 * Originally Released Under LGPL - original licence link has changed is not relivant.
51528 * <script type="text/javascript">
51532 * @class Roo.BasicLayoutRegion
51533 * @extends Roo.util.Observable
51534 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51535 * and does not have a titlebar, tabs or any other features. All it does is size and position
51536 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51538 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51540 this.position = pos;
51543 * @scope Roo.BasicLayoutRegion
51547 * @event beforeremove
51548 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51549 * @param {Roo.LayoutRegion} this
51550 * @param {Roo.ContentPanel} panel The panel
51551 * @param {Object} e The cancel event object
51553 "beforeremove" : true,
51555 * @event invalidated
51556 * Fires when the layout for this region is changed.
51557 * @param {Roo.LayoutRegion} this
51559 "invalidated" : true,
51561 * @event visibilitychange
51562 * Fires when this region is shown or hidden
51563 * @param {Roo.LayoutRegion} this
51564 * @param {Boolean} visibility true or false
51566 "visibilitychange" : true,
51568 * @event paneladded
51569 * Fires when a panel is added.
51570 * @param {Roo.LayoutRegion} this
51571 * @param {Roo.ContentPanel} panel The panel
51573 "paneladded" : true,
51575 * @event panelremoved
51576 * Fires when a panel is removed.
51577 * @param {Roo.LayoutRegion} this
51578 * @param {Roo.ContentPanel} panel The panel
51580 "panelremoved" : true,
51582 * @event beforecollapse
51583 * Fires when this region before collapse.
51584 * @param {Roo.LayoutRegion} this
51586 "beforecollapse" : true,
51589 * Fires when this region is collapsed.
51590 * @param {Roo.LayoutRegion} this
51592 "collapsed" : true,
51595 * Fires when this region is expanded.
51596 * @param {Roo.LayoutRegion} this
51601 * Fires when this region is slid into view.
51602 * @param {Roo.LayoutRegion} this
51604 "slideshow" : true,
51607 * Fires when this region slides out of view.
51608 * @param {Roo.LayoutRegion} this
51610 "slidehide" : true,
51612 * @event panelactivated
51613 * Fires when a panel is activated.
51614 * @param {Roo.LayoutRegion} this
51615 * @param {Roo.ContentPanel} panel The activated panel
51617 "panelactivated" : true,
51620 * Fires when the user resizes this region.
51621 * @param {Roo.LayoutRegion} this
51622 * @param {Number} newSize The new size (width for east/west, height for north/south)
51626 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51627 this.panels = new Roo.util.MixedCollection();
51628 this.panels.getKey = this.getPanelId.createDelegate(this);
51630 this.activePanel = null;
51631 // ensure listeners are added...
51633 if (config.listeners || config.events) {
51634 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51635 listeners : config.listeners || {},
51636 events : config.events || {}
51640 if(skipConfig !== true){
51641 this.applyConfig(config);
51645 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51646 getPanelId : function(p){
51650 applyConfig : function(config){
51651 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51652 this.config = config;
51657 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51658 * the width, for horizontal (north, south) the height.
51659 * @param {Number} newSize The new width or height
51661 resizeTo : function(newSize){
51662 var el = this.el ? this.el :
51663 (this.activePanel ? this.activePanel.getEl() : null);
51665 switch(this.position){
51668 el.setWidth(newSize);
51669 this.fireEvent("resized", this, newSize);
51673 el.setHeight(newSize);
51674 this.fireEvent("resized", this, newSize);
51680 getBox : function(){
51681 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51684 getMargins : function(){
51685 return this.margins;
51688 updateBox : function(box){
51690 var el = this.activePanel.getEl();
51691 el.dom.style.left = box.x + "px";
51692 el.dom.style.top = box.y + "px";
51693 this.activePanel.setSize(box.width, box.height);
51697 * Returns the container element for this region.
51698 * @return {Roo.Element}
51700 getEl : function(){
51701 return this.activePanel;
51705 * Returns true if this region is currently visible.
51706 * @return {Boolean}
51708 isVisible : function(){
51709 return this.activePanel ? true : false;
51712 setActivePanel : function(panel){
51713 panel = this.getPanel(panel);
51714 if(this.activePanel && this.activePanel != panel){
51715 this.activePanel.setActiveState(false);
51716 this.activePanel.getEl().setLeftTop(-10000,-10000);
51718 this.activePanel = panel;
51719 panel.setActiveState(true);
51721 panel.setSize(this.box.width, this.box.height);
51723 this.fireEvent("panelactivated", this, panel);
51724 this.fireEvent("invalidated");
51728 * Show the specified panel.
51729 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51730 * @return {Roo.ContentPanel} The shown panel or null
51732 showPanel : function(panel){
51733 if(panel = this.getPanel(panel)){
51734 this.setActivePanel(panel);
51740 * Get the active panel for this region.
51741 * @return {Roo.ContentPanel} The active panel or null
51743 getActivePanel : function(){
51744 return this.activePanel;
51748 * Add the passed ContentPanel(s)
51749 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51750 * @return {Roo.ContentPanel} The panel added (if only one was added)
51752 add : function(panel){
51753 if(arguments.length > 1){
51754 for(var i = 0, len = arguments.length; i < len; i++) {
51755 this.add(arguments[i]);
51759 if(this.hasPanel(panel)){
51760 this.showPanel(panel);
51763 var el = panel.getEl();
51764 if(el.dom.parentNode != this.mgr.el.dom){
51765 this.mgr.el.dom.appendChild(el.dom);
51767 if(panel.setRegion){
51768 panel.setRegion(this);
51770 this.panels.add(panel);
51771 el.setStyle("position", "absolute");
51772 if(!panel.background){
51773 this.setActivePanel(panel);
51774 if(this.config.initialSize && this.panels.getCount()==1){
51775 this.resizeTo(this.config.initialSize);
51778 this.fireEvent("paneladded", this, panel);
51783 * Returns true if the panel is in this region.
51784 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51785 * @return {Boolean}
51787 hasPanel : function(panel){
51788 if(typeof panel == "object"){ // must be panel obj
51789 panel = panel.getId();
51791 return this.getPanel(panel) ? true : false;
51795 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51796 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51797 * @param {Boolean} preservePanel Overrides the config preservePanel option
51798 * @return {Roo.ContentPanel} The panel that was removed
51800 remove : function(panel, preservePanel){
51801 panel = this.getPanel(panel);
51806 this.fireEvent("beforeremove", this, panel, e);
51807 if(e.cancel === true){
51810 var panelId = panel.getId();
51811 this.panels.removeKey(panelId);
51816 * Returns the panel specified or null if it's not in this region.
51817 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51818 * @return {Roo.ContentPanel}
51820 getPanel : function(id){
51821 if(typeof id == "object"){ // must be panel obj
51824 return this.panels.get(id);
51828 * Returns this regions position (north/south/east/west/center).
51831 getPosition: function(){
51832 return this.position;
51836 * Ext JS Library 1.1.1
51837 * Copyright(c) 2006-2007, Ext JS, LLC.
51839 * Originally Released Under LGPL - original licence link has changed is not relivant.
51842 * <script type="text/javascript">
51846 * @class Roo.LayoutRegion
51847 * @extends Roo.BasicLayoutRegion
51848 * This class represents a region in a layout manager.
51849 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51850 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51851 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51852 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51853 * @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})
51854 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51855 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51856 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51857 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51858 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51859 * @cfg {String} title The title for the region (overrides panel titles)
51860 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51861 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51862 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51863 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51864 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51865 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51866 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51867 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51868 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51869 * @cfg {Boolean} showPin True to show a pin button
51870 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51871 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51872 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51873 * @cfg {Number} width For East/West panels
51874 * @cfg {Number} height For North/South panels
51875 * @cfg {Boolean} split To show the splitter
51876 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51878 Roo.LayoutRegion = function(mgr, config, pos){
51879 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51880 var dh = Roo.DomHelper;
51881 /** This region's container element
51882 * @type Roo.Element */
51883 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51884 /** This region's title element
51885 * @type Roo.Element */
51887 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51888 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51889 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51891 this.titleEl.enableDisplayMode();
51892 /** This region's title text element
51893 * @type HTMLElement */
51894 this.titleTextEl = this.titleEl.dom.firstChild;
51895 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51896 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51897 this.closeBtn.enableDisplayMode();
51898 this.closeBtn.on("click", this.closeClicked, this);
51899 this.closeBtn.hide();
51901 this.createBody(config);
51902 this.visible = true;
51903 this.collapsed = false;
51905 if(config.hideWhenEmpty){
51907 this.on("paneladded", this.validateVisibility, this);
51908 this.on("panelremoved", this.validateVisibility, this);
51910 this.applyConfig(config);
51913 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51915 createBody : function(){
51916 /** This region's body element
51917 * @type Roo.Element */
51918 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51921 applyConfig : function(c){
51922 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51923 var dh = Roo.DomHelper;
51924 if(c.titlebar !== false){
51925 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51926 this.collapseBtn.on("click", this.collapse, this);
51927 this.collapseBtn.enableDisplayMode();
51929 if(c.showPin === true || this.showPin){
51930 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51931 this.stickBtn.enableDisplayMode();
51932 this.stickBtn.on("click", this.expand, this);
51933 this.stickBtn.hide();
51936 /** This region's collapsed element
51937 * @type Roo.Element */
51938 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51939 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51941 if(c.floatable !== false){
51942 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51943 this.collapsedEl.on("click", this.collapseClick, this);
51946 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51947 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51948 id: "message", unselectable: "on", style:{"float":"left"}});
51949 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51951 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51952 this.expandBtn.on("click", this.expand, this);
51954 if(this.collapseBtn){
51955 this.collapseBtn.setVisible(c.collapsible == true);
51957 this.cmargins = c.cmargins || this.cmargins ||
51958 (this.position == "west" || this.position == "east" ?
51959 {top: 0, left: 2, right:2, bottom: 0} :
51960 {top: 2, left: 0, right:0, bottom: 2});
51961 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51962 this.bottomTabs = c.tabPosition != "top";
51963 this.autoScroll = c.autoScroll || false;
51964 if(this.autoScroll){
51965 this.bodyEl.setStyle("overflow", "auto");
51967 this.bodyEl.setStyle("overflow", "hidden");
51969 //if(c.titlebar !== false){
51970 if((!c.titlebar && !c.title) || c.titlebar === false){
51971 this.titleEl.hide();
51973 this.titleEl.show();
51975 this.titleTextEl.innerHTML = c.title;
51979 this.duration = c.duration || .30;
51980 this.slideDuration = c.slideDuration || .45;
51983 this.collapse(true);
51990 * Returns true if this region is currently visible.
51991 * @return {Boolean}
51993 isVisible : function(){
51994 return this.visible;
51998 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
51999 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52001 setCollapsedTitle : function(title){
52002 title = title || " ";
52003 if(this.collapsedTitleTextEl){
52004 this.collapsedTitleTextEl.innerHTML = title;
52008 getBox : function(){
52010 if(!this.collapsed){
52011 b = this.el.getBox(false, true);
52013 b = this.collapsedEl.getBox(false, true);
52018 getMargins : function(){
52019 return this.collapsed ? this.cmargins : this.margins;
52022 highlight : function(){
52023 this.el.addClass("x-layout-panel-dragover");
52026 unhighlight : function(){
52027 this.el.removeClass("x-layout-panel-dragover");
52030 updateBox : function(box){
52032 if(!this.collapsed){
52033 this.el.dom.style.left = box.x + "px";
52034 this.el.dom.style.top = box.y + "px";
52035 this.updateBody(box.width, box.height);
52037 this.collapsedEl.dom.style.left = box.x + "px";
52038 this.collapsedEl.dom.style.top = box.y + "px";
52039 this.collapsedEl.setSize(box.width, box.height);
52042 this.tabs.autoSizeTabs();
52046 updateBody : function(w, h){
52048 this.el.setWidth(w);
52049 w -= this.el.getBorderWidth("rl");
52050 if(this.config.adjustments){
52051 w += this.config.adjustments[0];
52055 this.el.setHeight(h);
52056 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52057 h -= this.el.getBorderWidth("tb");
52058 if(this.config.adjustments){
52059 h += this.config.adjustments[1];
52061 this.bodyEl.setHeight(h);
52063 h = this.tabs.syncHeight(h);
52066 if(this.panelSize){
52067 w = w !== null ? w : this.panelSize.width;
52068 h = h !== null ? h : this.panelSize.height;
52070 if(this.activePanel){
52071 var el = this.activePanel.getEl();
52072 w = w !== null ? w : el.getWidth();
52073 h = h !== null ? h : el.getHeight();
52074 this.panelSize = {width: w, height: h};
52075 this.activePanel.setSize(w, h);
52077 if(Roo.isIE && this.tabs){
52078 this.tabs.el.repaint();
52083 * Returns the container element for this region.
52084 * @return {Roo.Element}
52086 getEl : function(){
52091 * Hides this region.
52094 if(!this.collapsed){
52095 this.el.dom.style.left = "-2000px";
52098 this.collapsedEl.dom.style.left = "-2000px";
52099 this.collapsedEl.hide();
52101 this.visible = false;
52102 this.fireEvent("visibilitychange", this, false);
52106 * Shows this region if it was previously hidden.
52109 if(!this.collapsed){
52112 this.collapsedEl.show();
52114 this.visible = true;
52115 this.fireEvent("visibilitychange", this, true);
52118 closeClicked : function(){
52119 if(this.activePanel){
52120 this.remove(this.activePanel);
52124 collapseClick : function(e){
52126 e.stopPropagation();
52129 e.stopPropagation();
52135 * Collapses this region.
52136 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52138 collapse : function(skipAnim, skipCheck = false){
52139 if(this.collapsed) {
52143 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52145 this.collapsed = true;
52147 this.split.el.hide();
52149 if(this.config.animate && skipAnim !== true){
52150 this.fireEvent("invalidated", this);
52151 this.animateCollapse();
52153 this.el.setLocation(-20000,-20000);
52155 this.collapsedEl.show();
52156 this.fireEvent("collapsed", this);
52157 this.fireEvent("invalidated", this);
52163 animateCollapse : function(){
52168 * Expands this region if it was previously collapsed.
52169 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52170 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52172 expand : function(e, skipAnim){
52174 e.stopPropagation();
52176 if(!this.collapsed || this.el.hasActiveFx()) {
52180 this.afterSlideIn();
52183 this.collapsed = false;
52184 if(this.config.animate && skipAnim !== true){
52185 this.animateExpand();
52189 this.split.el.show();
52191 this.collapsedEl.setLocation(-2000,-2000);
52192 this.collapsedEl.hide();
52193 this.fireEvent("invalidated", this);
52194 this.fireEvent("expanded", this);
52198 animateExpand : function(){
52202 initTabs : function()
52204 this.bodyEl.setStyle("overflow", "hidden");
52205 var ts = new Roo.TabPanel(
52208 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52209 disableTooltips: this.config.disableTabTips,
52210 toolbar : this.config.toolbar
52213 if(this.config.hideTabs){
52214 ts.stripWrap.setDisplayed(false);
52217 ts.resizeTabs = this.config.resizeTabs === true;
52218 ts.minTabWidth = this.config.minTabWidth || 40;
52219 ts.maxTabWidth = this.config.maxTabWidth || 250;
52220 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52221 ts.monitorResize = false;
52222 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52223 ts.bodyEl.addClass('x-layout-tabs-body');
52224 this.panels.each(this.initPanelAsTab, this);
52227 initPanelAsTab : function(panel){
52228 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52229 this.config.closeOnTab && panel.isClosable());
52230 if(panel.tabTip !== undefined){
52231 ti.setTooltip(panel.tabTip);
52233 ti.on("activate", function(){
52234 this.setActivePanel(panel);
52236 if(this.config.closeOnTab){
52237 ti.on("beforeclose", function(t, e){
52239 this.remove(panel);
52245 updatePanelTitle : function(panel, title){
52246 if(this.activePanel == panel){
52247 this.updateTitle(title);
52250 var ti = this.tabs.getTab(panel.getEl().id);
52252 if(panel.tabTip !== undefined){
52253 ti.setTooltip(panel.tabTip);
52258 updateTitle : function(title){
52259 if(this.titleTextEl && !this.config.title){
52260 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52264 setActivePanel : function(panel){
52265 panel = this.getPanel(panel);
52266 if(this.activePanel && this.activePanel != panel){
52267 this.activePanel.setActiveState(false);
52269 this.activePanel = panel;
52270 panel.setActiveState(true);
52271 if(this.panelSize){
52272 panel.setSize(this.panelSize.width, this.panelSize.height);
52275 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52277 this.updateTitle(panel.getTitle());
52279 this.fireEvent("invalidated", this);
52281 this.fireEvent("panelactivated", this, panel);
52285 * Shows the specified panel.
52286 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52287 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52289 showPanel : function(panel)
52291 panel = this.getPanel(panel);
52294 var tab = this.tabs.getTab(panel.getEl().id);
52295 if(tab.isHidden()){
52296 this.tabs.unhideTab(tab.id);
52300 this.setActivePanel(panel);
52307 * Get the active panel for this region.
52308 * @return {Roo.ContentPanel} The active panel or null
52310 getActivePanel : function(){
52311 return this.activePanel;
52314 validateVisibility : function(){
52315 if(this.panels.getCount() < 1){
52316 this.updateTitle(" ");
52317 this.closeBtn.hide();
52320 if(!this.isVisible()){
52327 * Adds the passed ContentPanel(s) to this region.
52328 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52329 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52331 add : function(panel){
52332 if(arguments.length > 1){
52333 for(var i = 0, len = arguments.length; i < len; i++) {
52334 this.add(arguments[i]);
52338 if(this.hasPanel(panel)){
52339 this.showPanel(panel);
52342 panel.setRegion(this);
52343 this.panels.add(panel);
52344 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52345 this.bodyEl.dom.appendChild(panel.getEl().dom);
52346 if(panel.background !== true){
52347 this.setActivePanel(panel);
52349 this.fireEvent("paneladded", this, panel);
52355 this.initPanelAsTab(panel);
52357 if(panel.background !== true){
52358 this.tabs.activate(panel.getEl().id);
52360 this.fireEvent("paneladded", this, panel);
52365 * Hides the tab for the specified panel.
52366 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52368 hidePanel : function(panel){
52369 if(this.tabs && (panel = this.getPanel(panel))){
52370 this.tabs.hideTab(panel.getEl().id);
52375 * Unhides the tab for a previously hidden panel.
52376 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52378 unhidePanel : function(panel){
52379 if(this.tabs && (panel = this.getPanel(panel))){
52380 this.tabs.unhideTab(panel.getEl().id);
52384 clearPanels : function(){
52385 while(this.panels.getCount() > 0){
52386 this.remove(this.panels.first());
52391 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52392 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52393 * @param {Boolean} preservePanel Overrides the config preservePanel option
52394 * @return {Roo.ContentPanel} The panel that was removed
52396 remove : function(panel, preservePanel){
52397 panel = this.getPanel(panel);
52402 this.fireEvent("beforeremove", this, panel, e);
52403 if(e.cancel === true){
52406 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52407 var panelId = panel.getId();
52408 this.panels.removeKey(panelId);
52410 document.body.appendChild(panel.getEl().dom);
52413 this.tabs.removeTab(panel.getEl().id);
52414 }else if (!preservePanel){
52415 this.bodyEl.dom.removeChild(panel.getEl().dom);
52417 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52418 var p = this.panels.first();
52419 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52420 tempEl.appendChild(p.getEl().dom);
52421 this.bodyEl.update("");
52422 this.bodyEl.dom.appendChild(p.getEl().dom);
52424 this.updateTitle(p.getTitle());
52426 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52427 this.setActivePanel(p);
52429 panel.setRegion(null);
52430 if(this.activePanel == panel){
52431 this.activePanel = null;
52433 if(this.config.autoDestroy !== false && preservePanel !== true){
52434 try{panel.destroy();}catch(e){}
52436 this.fireEvent("panelremoved", this, panel);
52441 * Returns the TabPanel component used by this region
52442 * @return {Roo.TabPanel}
52444 getTabs : function(){
52448 createTool : function(parentEl, className){
52449 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52450 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52451 btn.addClassOnOver("x-layout-tools-button-over");
52456 * Ext JS Library 1.1.1
52457 * Copyright(c) 2006-2007, Ext JS, LLC.
52459 * Originally Released Under LGPL - original licence link has changed is not relivant.
52462 * <script type="text/javascript">
52468 * @class Roo.SplitLayoutRegion
52469 * @extends Roo.LayoutRegion
52470 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52472 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52473 this.cursor = cursor;
52474 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52477 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52478 splitTip : "Drag to resize.",
52479 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52480 useSplitTips : false,
52482 applyConfig : function(config){
52483 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52486 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52487 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52488 /** The SplitBar for this region
52489 * @type Roo.SplitBar */
52490 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52491 this.split.on("moved", this.onSplitMove, this);
52492 this.split.useShim = config.useShim === true;
52493 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52494 if(this.useSplitTips){
52495 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52497 if(config.collapsible){
52498 this.split.el.on("dblclick", this.collapse, this);
52501 if(typeof config.minSize != "undefined"){
52502 this.split.minSize = config.minSize;
52504 if(typeof config.maxSize != "undefined"){
52505 this.split.maxSize = config.maxSize;
52507 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52508 this.hideSplitter();
52513 getHMaxSize : function(){
52514 var cmax = this.config.maxSize || 10000;
52515 var center = this.mgr.getRegion("center");
52516 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52519 getVMaxSize : function(){
52520 var cmax = this.config.maxSize || 10000;
52521 var center = this.mgr.getRegion("center");
52522 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52525 onSplitMove : function(split, newSize){
52526 this.fireEvent("resized", this, newSize);
52530 * Returns the {@link Roo.SplitBar} for this region.
52531 * @return {Roo.SplitBar}
52533 getSplitBar : function(){
52538 this.hideSplitter();
52539 Roo.SplitLayoutRegion.superclass.hide.call(this);
52542 hideSplitter : function(){
52544 this.split.el.setLocation(-2000,-2000);
52545 this.split.el.hide();
52551 this.split.el.show();
52553 Roo.SplitLayoutRegion.superclass.show.call(this);
52556 beforeSlide: function(){
52557 if(Roo.isGecko){// firefox overflow auto bug workaround
52558 this.bodyEl.clip();
52560 this.tabs.bodyEl.clip();
52562 if(this.activePanel){
52563 this.activePanel.getEl().clip();
52565 if(this.activePanel.beforeSlide){
52566 this.activePanel.beforeSlide();
52572 afterSlide : function(){
52573 if(Roo.isGecko){// firefox overflow auto bug workaround
52574 this.bodyEl.unclip();
52576 this.tabs.bodyEl.unclip();
52578 if(this.activePanel){
52579 this.activePanel.getEl().unclip();
52580 if(this.activePanel.afterSlide){
52581 this.activePanel.afterSlide();
52587 initAutoHide : function(){
52588 if(this.autoHide !== false){
52589 if(!this.autoHideHd){
52590 var st = new Roo.util.DelayedTask(this.slideIn, this);
52591 this.autoHideHd = {
52592 "mouseout": function(e){
52593 if(!e.within(this.el, true)){
52597 "mouseover" : function(e){
52603 this.el.on(this.autoHideHd);
52607 clearAutoHide : function(){
52608 if(this.autoHide !== false){
52609 this.el.un("mouseout", this.autoHideHd.mouseout);
52610 this.el.un("mouseover", this.autoHideHd.mouseover);
52614 clearMonitor : function(){
52615 Roo.get(document).un("click", this.slideInIf, this);
52618 // these names are backwards but not changed for compat
52619 slideOut : function(){
52620 if(this.isSlid || this.el.hasActiveFx()){
52623 this.isSlid = true;
52624 if(this.collapseBtn){
52625 this.collapseBtn.hide();
52627 this.closeBtnState = this.closeBtn.getStyle('display');
52628 this.closeBtn.hide();
52630 this.stickBtn.show();
52633 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52634 this.beforeSlide();
52635 this.el.setStyle("z-index", 10001);
52636 this.el.slideIn(this.getSlideAnchor(), {
52637 callback: function(){
52639 this.initAutoHide();
52640 Roo.get(document).on("click", this.slideInIf, this);
52641 this.fireEvent("slideshow", this);
52648 afterSlideIn : function(){
52649 this.clearAutoHide();
52650 this.isSlid = false;
52651 this.clearMonitor();
52652 this.el.setStyle("z-index", "");
52653 if(this.collapseBtn){
52654 this.collapseBtn.show();
52656 this.closeBtn.setStyle('display', this.closeBtnState);
52658 this.stickBtn.hide();
52660 this.fireEvent("slidehide", this);
52663 slideIn : function(cb){
52664 if(!this.isSlid || this.el.hasActiveFx()){
52668 this.isSlid = false;
52669 this.beforeSlide();
52670 this.el.slideOut(this.getSlideAnchor(), {
52671 callback: function(){
52672 this.el.setLeftTop(-10000, -10000);
52674 this.afterSlideIn();
52682 slideInIf : function(e){
52683 if(!e.within(this.el)){
52688 animateCollapse : function(){
52689 this.beforeSlide();
52690 this.el.setStyle("z-index", 20000);
52691 var anchor = this.getSlideAnchor();
52692 this.el.slideOut(anchor, {
52693 callback : function(){
52694 this.el.setStyle("z-index", "");
52695 this.collapsedEl.slideIn(anchor, {duration:.3});
52697 this.el.setLocation(-10000,-10000);
52699 this.fireEvent("collapsed", this);
52706 animateExpand : function(){
52707 this.beforeSlide();
52708 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52709 this.el.setStyle("z-index", 20000);
52710 this.collapsedEl.hide({
52713 this.el.slideIn(this.getSlideAnchor(), {
52714 callback : function(){
52715 this.el.setStyle("z-index", "");
52718 this.split.el.show();
52720 this.fireEvent("invalidated", this);
52721 this.fireEvent("expanded", this);
52749 getAnchor : function(){
52750 return this.anchors[this.position];
52753 getCollapseAnchor : function(){
52754 return this.canchors[this.position];
52757 getSlideAnchor : function(){
52758 return this.sanchors[this.position];
52761 getAlignAdj : function(){
52762 var cm = this.cmargins;
52763 switch(this.position){
52779 getExpandAdj : function(){
52780 var c = this.collapsedEl, cm = this.cmargins;
52781 switch(this.position){
52783 return [-(cm.right+c.getWidth()+cm.left), 0];
52786 return [cm.right+c.getWidth()+cm.left, 0];
52789 return [0, -(cm.top+cm.bottom+c.getHeight())];
52792 return [0, cm.top+cm.bottom+c.getHeight()];
52798 * Ext JS Library 1.1.1
52799 * Copyright(c) 2006-2007, Ext JS, LLC.
52801 * Originally Released Under LGPL - original licence link has changed is not relivant.
52804 * <script type="text/javascript">
52807 * These classes are private internal classes
52809 Roo.CenterLayoutRegion = function(mgr, config){
52810 Roo.LayoutRegion.call(this, mgr, config, "center");
52811 this.visible = true;
52812 this.minWidth = config.minWidth || 20;
52813 this.minHeight = config.minHeight || 20;
52816 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52818 // center panel can't be hidden
52822 // center panel can't be hidden
52825 getMinWidth: function(){
52826 return this.minWidth;
52829 getMinHeight: function(){
52830 return this.minHeight;
52835 Roo.NorthLayoutRegion = function(mgr, config){
52836 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52838 this.split.placement = Roo.SplitBar.TOP;
52839 this.split.orientation = Roo.SplitBar.VERTICAL;
52840 this.split.el.addClass("x-layout-split-v");
52842 var size = config.initialSize || config.height;
52843 if(typeof size != "undefined"){
52844 this.el.setHeight(size);
52847 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52848 orientation: Roo.SplitBar.VERTICAL,
52849 getBox : function(){
52850 if(this.collapsed){
52851 return this.collapsedEl.getBox();
52853 var box = this.el.getBox();
52855 box.height += this.split.el.getHeight();
52860 updateBox : function(box){
52861 if(this.split && !this.collapsed){
52862 box.height -= this.split.el.getHeight();
52863 this.split.el.setLeft(box.x);
52864 this.split.el.setTop(box.y+box.height);
52865 this.split.el.setWidth(box.width);
52867 if(this.collapsed){
52868 this.updateBody(box.width, null);
52870 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52874 Roo.SouthLayoutRegion = function(mgr, config){
52875 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52877 this.split.placement = Roo.SplitBar.BOTTOM;
52878 this.split.orientation = Roo.SplitBar.VERTICAL;
52879 this.split.el.addClass("x-layout-split-v");
52881 var size = config.initialSize || config.height;
52882 if(typeof size != "undefined"){
52883 this.el.setHeight(size);
52886 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52887 orientation: Roo.SplitBar.VERTICAL,
52888 getBox : function(){
52889 if(this.collapsed){
52890 return this.collapsedEl.getBox();
52892 var box = this.el.getBox();
52894 var sh = this.split.el.getHeight();
52901 updateBox : function(box){
52902 if(this.split && !this.collapsed){
52903 var sh = this.split.el.getHeight();
52906 this.split.el.setLeft(box.x);
52907 this.split.el.setTop(box.y-sh);
52908 this.split.el.setWidth(box.width);
52910 if(this.collapsed){
52911 this.updateBody(box.width, null);
52913 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52917 Roo.EastLayoutRegion = function(mgr, config){
52918 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52920 this.split.placement = Roo.SplitBar.RIGHT;
52921 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52922 this.split.el.addClass("x-layout-split-h");
52924 var size = config.initialSize || config.width;
52925 if(typeof size != "undefined"){
52926 this.el.setWidth(size);
52929 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52930 orientation: Roo.SplitBar.HORIZONTAL,
52931 getBox : function(){
52932 if(this.collapsed){
52933 return this.collapsedEl.getBox();
52935 var box = this.el.getBox();
52937 var sw = this.split.el.getWidth();
52944 updateBox : function(box){
52945 if(this.split && !this.collapsed){
52946 var sw = this.split.el.getWidth();
52948 this.split.el.setLeft(box.x);
52949 this.split.el.setTop(box.y);
52950 this.split.el.setHeight(box.height);
52953 if(this.collapsed){
52954 this.updateBody(null, box.height);
52956 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52960 Roo.WestLayoutRegion = function(mgr, config){
52961 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52963 this.split.placement = Roo.SplitBar.LEFT;
52964 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52965 this.split.el.addClass("x-layout-split-h");
52967 var size = config.initialSize || config.width;
52968 if(typeof size != "undefined"){
52969 this.el.setWidth(size);
52972 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52973 orientation: Roo.SplitBar.HORIZONTAL,
52974 getBox : function(){
52975 if(this.collapsed){
52976 return this.collapsedEl.getBox();
52978 var box = this.el.getBox();
52980 box.width += this.split.el.getWidth();
52985 updateBox : function(box){
52986 if(this.split && !this.collapsed){
52987 var sw = this.split.el.getWidth();
52989 this.split.el.setLeft(box.x+box.width);
52990 this.split.el.setTop(box.y);
52991 this.split.el.setHeight(box.height);
52993 if(this.collapsed){
52994 this.updateBody(null, box.height);
52996 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53001 * Ext JS Library 1.1.1
53002 * Copyright(c) 2006-2007, Ext JS, LLC.
53004 * Originally Released Under LGPL - original licence link has changed is not relivant.
53007 * <script type="text/javascript">
53012 * Private internal class for reading and applying state
53014 Roo.LayoutStateManager = function(layout){
53015 // default empty state
53024 Roo.LayoutStateManager.prototype = {
53025 init : function(layout, provider){
53026 this.provider = provider;
53027 var state = provider.get(layout.id+"-layout-state");
53029 var wasUpdating = layout.isUpdating();
53031 layout.beginUpdate();
53033 for(var key in state){
53034 if(typeof state[key] != "function"){
53035 var rstate = state[key];
53036 var r = layout.getRegion(key);
53039 r.resizeTo(rstate.size);
53041 if(rstate.collapsed == true){
53044 r.expand(null, true);
53050 layout.endUpdate();
53052 this.state = state;
53054 this.layout = layout;
53055 layout.on("regionresized", this.onRegionResized, this);
53056 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53057 layout.on("regionexpanded", this.onRegionExpanded, this);
53060 storeState : function(){
53061 this.provider.set(this.layout.id+"-layout-state", this.state);
53064 onRegionResized : function(region, newSize){
53065 this.state[region.getPosition()].size = newSize;
53069 onRegionCollapsed : function(region){
53070 this.state[region.getPosition()].collapsed = true;
53074 onRegionExpanded : function(region){
53075 this.state[region.getPosition()].collapsed = false;
53080 * Ext JS Library 1.1.1
53081 * Copyright(c) 2006-2007, Ext JS, LLC.
53083 * Originally Released Under LGPL - original licence link has changed is not relivant.
53086 * <script type="text/javascript">
53089 * @class Roo.ContentPanel
53090 * @extends Roo.util.Observable
53091 * A basic ContentPanel element.
53092 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53093 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53094 * @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
53095 * @cfg {Boolean} closable True if the panel can be closed/removed
53096 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53097 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53098 * @cfg {Toolbar} toolbar A toolbar for this panel
53099 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53100 * @cfg {String} title The title for this panel
53101 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53102 * @cfg {String} url Calls {@link #setUrl} with this value
53103 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53104 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53105 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53106 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53109 * Create a new ContentPanel.
53110 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53111 * @param {String/Object} config A string to set only the title or a config object
53112 * @param {String} content (optional) Set the HTML content for this panel
53113 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53115 Roo.ContentPanel = function(el, config, content){
53119 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53123 if (config && config.parentLayout) {
53124 el = config.parentLayout.el.createChild();
53127 if(el.autoCreate){ // xtype is available if this is called from factory
53131 this.el = Roo.get(el);
53132 if(!this.el && config && config.autoCreate){
53133 if(typeof config.autoCreate == "object"){
53134 if(!config.autoCreate.id){
53135 config.autoCreate.id = config.id||el;
53137 this.el = Roo.DomHelper.append(document.body,
53138 config.autoCreate, true);
53140 this.el = Roo.DomHelper.append(document.body,
53141 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53144 this.closable = false;
53145 this.loaded = false;
53146 this.active = false;
53147 if(typeof config == "string"){
53148 this.title = config;
53150 Roo.apply(this, config);
53153 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53154 this.wrapEl = this.el.wrap();
53155 this.toolbar.container = this.el.insertSibling(false, 'before');
53156 this.toolbar = new Roo.Toolbar(this.toolbar);
53159 // xtype created footer. - not sure if will work as we normally have to render first..
53160 if (this.footer && !this.footer.el && this.footer.xtype) {
53161 if (!this.wrapEl) {
53162 this.wrapEl = this.el.wrap();
53165 this.footer.container = this.wrapEl.createChild();
53167 this.footer = Roo.factory(this.footer, Roo);
53172 this.resizeEl = Roo.get(this.resizeEl, true);
53174 this.resizeEl = this.el;
53176 // handle view.xtype
53184 * Fires when this panel is activated.
53185 * @param {Roo.ContentPanel} this
53189 * @event deactivate
53190 * Fires when this panel is activated.
53191 * @param {Roo.ContentPanel} this
53193 "deactivate" : true,
53197 * Fires when this panel is resized if fitToFrame is true.
53198 * @param {Roo.ContentPanel} this
53199 * @param {Number} width The width after any component adjustments
53200 * @param {Number} height The height after any component adjustments
53206 * Fires when this tab is created
53207 * @param {Roo.ContentPanel} this
53218 if(this.autoScroll){
53219 this.resizeEl.setStyle("overflow", "auto");
53221 // fix randome scrolling
53222 this.el.on('scroll', function() {
53223 Roo.log('fix random scolling');
53224 this.scrollTo('top',0);
53227 content = content || this.content;
53229 this.setContent(content);
53231 if(config && config.url){
53232 this.setUrl(this.url, this.params, this.loadOnce);
53237 Roo.ContentPanel.superclass.constructor.call(this);
53239 if (this.view && typeof(this.view.xtype) != 'undefined') {
53240 this.view.el = this.el.appendChild(document.createElement("div"));
53241 this.view = Roo.factory(this.view);
53242 this.view.render && this.view.render(false, '');
53246 this.fireEvent('render', this);
53249 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53251 setRegion : function(region){
53252 this.region = region;
53254 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53256 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53261 * Returns the toolbar for this Panel if one was configured.
53262 * @return {Roo.Toolbar}
53264 getToolbar : function(){
53265 return this.toolbar;
53268 setActiveState : function(active){
53269 this.active = active;
53271 this.fireEvent("deactivate", this);
53273 this.fireEvent("activate", this);
53277 * Updates this panel's element
53278 * @param {String} content The new content
53279 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53281 setContent : function(content, loadScripts){
53282 this.el.update(content, loadScripts);
53285 ignoreResize : function(w, h){
53286 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53289 this.lastSize = {width: w, height: h};
53294 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53295 * @return {Roo.UpdateManager} The UpdateManager
53297 getUpdateManager : function(){
53298 return this.el.getUpdateManager();
53301 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53302 * @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:
53305 url: "your-url.php",
53306 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53307 callback: yourFunction,
53308 scope: yourObject, //(optional scope)
53311 text: "Loading...",
53316 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53317 * 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.
53318 * @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}
53319 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53320 * @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.
53321 * @return {Roo.ContentPanel} this
53324 var um = this.el.getUpdateManager();
53325 um.update.apply(um, arguments);
53331 * 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.
53332 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53333 * @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)
53334 * @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)
53335 * @return {Roo.UpdateManager} The UpdateManager
53337 setUrl : function(url, params, loadOnce){
53338 if(this.refreshDelegate){
53339 this.removeListener("activate", this.refreshDelegate);
53341 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53342 this.on("activate", this.refreshDelegate);
53343 return this.el.getUpdateManager();
53346 _handleRefresh : function(url, params, loadOnce){
53347 if(!loadOnce || !this.loaded){
53348 var updater = this.el.getUpdateManager();
53349 updater.update(url, params, this._setLoaded.createDelegate(this));
53353 _setLoaded : function(){
53354 this.loaded = true;
53358 * Returns this panel's id
53361 getId : function(){
53366 * Returns this panel's element - used by regiosn to add.
53367 * @return {Roo.Element}
53369 getEl : function(){
53370 return this.wrapEl || this.el;
53373 adjustForComponents : function(width, height)
53375 //Roo.log('adjustForComponents ');
53376 if(this.resizeEl != this.el){
53377 width -= this.el.getFrameWidth('lr');
53378 height -= this.el.getFrameWidth('tb');
53381 var te = this.toolbar.getEl();
53382 height -= te.getHeight();
53383 te.setWidth(width);
53386 var te = this.footer.getEl();
53387 Roo.log("footer:" + te.getHeight());
53389 height -= te.getHeight();
53390 te.setWidth(width);
53394 if(this.adjustments){
53395 width += this.adjustments[0];
53396 height += this.adjustments[1];
53398 return {"width": width, "height": height};
53401 setSize : function(width, height){
53402 if(this.fitToFrame && !this.ignoreResize(width, height)){
53403 if(this.fitContainer && this.resizeEl != this.el){
53404 this.el.setSize(width, height);
53406 var size = this.adjustForComponents(width, height);
53407 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53408 this.fireEvent('resize', this, size.width, size.height);
53413 * Returns this panel's title
53416 getTitle : function(){
53421 * Set this panel's title
53422 * @param {String} title
53424 setTitle : function(title){
53425 this.title = title;
53427 this.region.updatePanelTitle(this, title);
53432 * Returns true is this panel was configured to be closable
53433 * @return {Boolean}
53435 isClosable : function(){
53436 return this.closable;
53439 beforeSlide : function(){
53441 this.resizeEl.clip();
53444 afterSlide : function(){
53446 this.resizeEl.unclip();
53450 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53451 * Will fail silently if the {@link #setUrl} method has not been called.
53452 * This does not activate the panel, just updates its content.
53454 refresh : function(){
53455 if(this.refreshDelegate){
53456 this.loaded = false;
53457 this.refreshDelegate();
53462 * Destroys this panel
53464 destroy : function(){
53465 this.el.removeAllListeners();
53466 var tempEl = document.createElement("span");
53467 tempEl.appendChild(this.el.dom);
53468 tempEl.innerHTML = "";
53474 * form - if the content panel contains a form - this is a reference to it.
53475 * @type {Roo.form.Form}
53479 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53480 * This contains a reference to it.
53486 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53496 * @param {Object} cfg Xtype definition of item to add.
53499 addxtype : function(cfg) {
53501 if (cfg.xtype.match(/^Form$/)) {
53504 //if (this.footer) {
53505 // el = this.footer.container.insertSibling(false, 'before');
53507 el = this.el.createChild();
53510 this.form = new Roo.form.Form(cfg);
53513 if ( this.form.allItems.length) {
53514 this.form.render(el.dom);
53518 // should only have one of theses..
53519 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53520 // views.. should not be just added - used named prop 'view''
53522 cfg.el = this.el.appendChild(document.createElement("div"));
53525 var ret = new Roo.factory(cfg);
53527 ret.render && ret.render(false, ''); // render blank..
53536 * @class Roo.GridPanel
53537 * @extends Roo.ContentPanel
53539 * Create a new GridPanel.
53540 * @param {Roo.grid.Grid} grid The grid for this panel
53541 * @param {String/Object} config A string to set only the panel's title, or a config object
53543 Roo.GridPanel = function(grid, config){
53546 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53547 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53549 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53551 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53554 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53556 // xtype created footer. - not sure if will work as we normally have to render first..
53557 if (this.footer && !this.footer.el && this.footer.xtype) {
53559 this.footer.container = this.grid.getView().getFooterPanel(true);
53560 this.footer.dataSource = this.grid.dataSource;
53561 this.footer = Roo.factory(this.footer, Roo);
53565 grid.monitorWindowResize = false; // turn off autosizing
53566 grid.autoHeight = false;
53567 grid.autoWidth = false;
53569 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53572 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53573 getId : function(){
53574 return this.grid.id;
53578 * Returns the grid for this panel
53579 * @return {Roo.grid.Grid}
53581 getGrid : function(){
53585 setSize : function(width, height){
53586 if(!this.ignoreResize(width, height)){
53587 var grid = this.grid;
53588 var size = this.adjustForComponents(width, height);
53589 grid.getGridEl().setSize(size.width, size.height);
53594 beforeSlide : function(){
53595 this.grid.getView().scroller.clip();
53598 afterSlide : function(){
53599 this.grid.getView().scroller.unclip();
53602 destroy : function(){
53603 this.grid.destroy();
53605 Roo.GridPanel.superclass.destroy.call(this);
53611 * @class Roo.NestedLayoutPanel
53612 * @extends Roo.ContentPanel
53614 * Create a new NestedLayoutPanel.
53617 * @param {Roo.BorderLayout} layout The layout for this panel
53618 * @param {String/Object} config A string to set only the title or a config object
53620 Roo.NestedLayoutPanel = function(layout, config)
53622 // construct with only one argument..
53623 /* FIXME - implement nicer consturctors
53624 if (layout.layout) {
53626 layout = config.layout;
53627 delete config.layout;
53629 if (layout.xtype && !layout.getEl) {
53630 // then layout needs constructing..
53631 layout = Roo.factory(layout, Roo);
53636 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53638 layout.monitorWindowResize = false; // turn off autosizing
53639 this.layout = layout;
53640 this.layout.getEl().addClass("x-layout-nested-layout");
53647 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53649 setSize : function(width, height){
53650 if(!this.ignoreResize(width, height)){
53651 var size = this.adjustForComponents(width, height);
53652 var el = this.layout.getEl();
53653 el.setSize(size.width, size.height);
53654 var touch = el.dom.offsetWidth;
53655 this.layout.layout();
53656 // ie requires a double layout on the first pass
53657 if(Roo.isIE && !this.initialized){
53658 this.initialized = true;
53659 this.layout.layout();
53664 // activate all subpanels if not currently active..
53666 setActiveState : function(active){
53667 this.active = active;
53669 this.fireEvent("deactivate", this);
53673 this.fireEvent("activate", this);
53674 // not sure if this should happen before or after..
53675 if (!this.layout) {
53676 return; // should not happen..
53679 for (var r in this.layout.regions) {
53680 reg = this.layout.getRegion(r);
53681 if (reg.getActivePanel()) {
53682 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53683 reg.setActivePanel(reg.getActivePanel());
53686 if (!reg.panels.length) {
53689 reg.showPanel(reg.getPanel(0));
53698 * Returns the nested BorderLayout for this panel
53699 * @return {Roo.BorderLayout}
53701 getLayout : function(){
53702 return this.layout;
53706 * Adds a xtype elements to the layout of the nested panel
53710 xtype : 'ContentPanel',
53717 xtype : 'NestedLayoutPanel',
53723 items : [ ... list of content panels or nested layout panels.. ]
53727 * @param {Object} cfg Xtype definition of item to add.
53729 addxtype : function(cfg) {
53730 return this.layout.addxtype(cfg);
53735 Roo.ScrollPanel = function(el, config, content){
53736 config = config || {};
53737 config.fitToFrame = true;
53738 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53740 this.el.dom.style.overflow = "hidden";
53741 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53742 this.el.removeClass("x-layout-inactive-content");
53743 this.el.on("mousewheel", this.onWheel, this);
53745 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53746 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53747 up.unselectable(); down.unselectable();
53748 up.on("click", this.scrollUp, this);
53749 down.on("click", this.scrollDown, this);
53750 up.addClassOnOver("x-scroller-btn-over");
53751 down.addClassOnOver("x-scroller-btn-over");
53752 up.addClassOnClick("x-scroller-btn-click");
53753 down.addClassOnClick("x-scroller-btn-click");
53754 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53756 this.resizeEl = this.el;
53757 this.el = wrap; this.up = up; this.down = down;
53760 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53762 wheelIncrement : 5,
53763 scrollUp : function(){
53764 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53767 scrollDown : function(){
53768 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53771 afterScroll : function(){
53772 var el = this.resizeEl;
53773 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53774 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53775 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53778 setSize : function(){
53779 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53780 this.afterScroll();
53783 onWheel : function(e){
53784 var d = e.getWheelDelta();
53785 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53786 this.afterScroll();
53790 setContent : function(content, loadScripts){
53791 this.resizeEl.update(content, loadScripts);
53805 * @class Roo.TreePanel
53806 * @extends Roo.ContentPanel
53808 * Create a new TreePanel. - defaults to fit/scoll contents.
53809 * @param {String/Object} config A string to set only the panel's title, or a config object
53810 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53812 Roo.TreePanel = function(config){
53813 var el = config.el;
53814 var tree = config.tree;
53815 delete config.tree;
53816 delete config.el; // hopefull!
53818 // wrapper for IE7 strict & safari scroll issue
53820 var treeEl = el.createChild();
53821 config.resizeEl = treeEl;
53825 Roo.TreePanel.superclass.constructor.call(this, el, config);
53828 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53829 //console.log(tree);
53830 this.on('activate', function()
53832 if (this.tree.rendered) {
53835 //console.log('render tree');
53836 this.tree.render();
53838 // this should not be needed.. - it's actually the 'el' that resizes?
53839 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53841 //this.on('resize', function (cp, w, h) {
53842 // this.tree.innerCt.setWidth(w);
53843 // this.tree.innerCt.setHeight(h);
53844 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53851 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53868 * Ext JS Library 1.1.1
53869 * Copyright(c) 2006-2007, Ext JS, LLC.
53871 * Originally Released Under LGPL - original licence link has changed is not relivant.
53874 * <script type="text/javascript">
53879 * @class Roo.ReaderLayout
53880 * @extends Roo.BorderLayout
53881 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53882 * center region containing two nested regions (a top one for a list view and one for item preview below),
53883 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53884 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53885 * expedites the setup of the overall layout and regions for this common application style.
53888 var reader = new Roo.ReaderLayout();
53889 var CP = Roo.ContentPanel; // shortcut for adding
53891 reader.beginUpdate();
53892 reader.add("north", new CP("north", "North"));
53893 reader.add("west", new CP("west", {title: "West"}));
53894 reader.add("east", new CP("east", {title: "East"}));
53896 reader.regions.listView.add(new CP("listView", "List"));
53897 reader.regions.preview.add(new CP("preview", "Preview"));
53898 reader.endUpdate();
53901 * Create a new ReaderLayout
53902 * @param {Object} config Configuration options
53903 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53904 * document.body if omitted)
53906 Roo.ReaderLayout = function(config, renderTo){
53907 var c = config || {size:{}};
53908 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53909 north: c.north !== false ? Roo.apply({
53913 }, c.north) : false,
53914 west: c.west !== false ? Roo.apply({
53922 margins:{left:5,right:0,bottom:5,top:5},
53923 cmargins:{left:5,right:5,bottom:5,top:5}
53924 }, c.west) : false,
53925 east: c.east !== false ? Roo.apply({
53933 margins:{left:0,right:5,bottom:5,top:5},
53934 cmargins:{left:5,right:5,bottom:5,top:5}
53935 }, c.east) : false,
53936 center: Roo.apply({
53937 tabPosition: 'top',
53941 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53945 this.el.addClass('x-reader');
53947 this.beginUpdate();
53949 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53950 south: c.preview !== false ? Roo.apply({
53957 cmargins:{top:5,left:0, right:0, bottom:0}
53958 }, c.preview) : false,
53959 center: Roo.apply({
53965 this.add('center', new Roo.NestedLayoutPanel(inner,
53966 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53970 this.regions.preview = inner.getRegion('south');
53971 this.regions.listView = inner.getRegion('center');
53974 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53976 * Ext JS Library 1.1.1
53977 * Copyright(c) 2006-2007, Ext JS, LLC.
53979 * Originally Released Under LGPL - original licence link has changed is not relivant.
53982 * <script type="text/javascript">
53986 * @class Roo.grid.Grid
53987 * @extends Roo.util.Observable
53988 * This class represents the primary interface of a component based grid control.
53989 * <br><br>Usage:<pre><code>
53990 var grid = new Roo.grid.Grid("my-container-id", {
53993 selModel: mySelectionModel,
53994 autoSizeColumns: true,
53995 monitorWindowResize: false,
53996 trackMouseOver: true
54001 * <b>Common Problems:</b><br/>
54002 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54003 * element will correct this<br/>
54004 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54005 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54006 * are unpredictable.<br/>
54007 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54008 * grid to calculate dimensions/offsets.<br/>
54010 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54011 * The container MUST have some type of size defined for the grid to fill. The container will be
54012 * automatically set to position relative if it isn't already.
54013 * @param {Object} config A config object that sets properties on this grid.
54015 Roo.grid.Grid = function(container, config){
54016 // initialize the container
54017 this.container = Roo.get(container);
54018 this.container.update("");
54019 this.container.setStyle("overflow", "hidden");
54020 this.container.addClass('x-grid-container');
54022 this.id = this.container.id;
54024 Roo.apply(this, config);
54025 // check and correct shorthanded configs
54027 this.dataSource = this.ds;
54031 this.colModel = this.cm;
54035 this.selModel = this.sm;
54039 if (this.selModel) {
54040 this.selModel = Roo.factory(this.selModel, Roo.grid);
54041 this.sm = this.selModel;
54042 this.sm.xmodule = this.xmodule || false;
54044 if (typeof(this.colModel.config) == 'undefined') {
54045 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54046 this.cm = this.colModel;
54047 this.cm.xmodule = this.xmodule || false;
54049 if (this.dataSource) {
54050 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54051 this.ds = this.dataSource;
54052 this.ds.xmodule = this.xmodule || false;
54059 this.container.setWidth(this.width);
54063 this.container.setHeight(this.height);
54070 * The raw click event for the entire grid.
54071 * @param {Roo.EventObject} e
54076 * The raw dblclick event for the entire grid.
54077 * @param {Roo.EventObject} e
54081 * @event contextmenu
54082 * The raw contextmenu event for the entire grid.
54083 * @param {Roo.EventObject} e
54085 "contextmenu" : true,
54088 * The raw mousedown event for the entire grid.
54089 * @param {Roo.EventObject} e
54091 "mousedown" : true,
54094 * The raw mouseup event for the entire grid.
54095 * @param {Roo.EventObject} e
54100 * The raw mouseover event for the entire grid.
54101 * @param {Roo.EventObject} e
54103 "mouseover" : true,
54106 * The raw mouseout event for the entire grid.
54107 * @param {Roo.EventObject} e
54112 * The raw keypress event for the entire grid.
54113 * @param {Roo.EventObject} e
54118 * The raw keydown event for the entire grid.
54119 * @param {Roo.EventObject} e
54127 * Fires when a cell is clicked
54128 * @param {Grid} this
54129 * @param {Number} rowIndex
54130 * @param {Number} columnIndex
54131 * @param {Roo.EventObject} e
54133 "cellclick" : true,
54135 * @event celldblclick
54136 * Fires when a cell is double clicked
54137 * @param {Grid} this
54138 * @param {Number} rowIndex
54139 * @param {Number} columnIndex
54140 * @param {Roo.EventObject} e
54142 "celldblclick" : true,
54145 * Fires when a row is clicked
54146 * @param {Grid} this
54147 * @param {Number} rowIndex
54148 * @param {Roo.EventObject} e
54152 * @event rowdblclick
54153 * Fires when a row is double clicked
54154 * @param {Grid} this
54155 * @param {Number} rowIndex
54156 * @param {Roo.EventObject} e
54158 "rowdblclick" : true,
54160 * @event headerclick
54161 * Fires when a header is clicked
54162 * @param {Grid} this
54163 * @param {Number} columnIndex
54164 * @param {Roo.EventObject} e
54166 "headerclick" : true,
54168 * @event headerdblclick
54169 * Fires when a header cell is double clicked
54170 * @param {Grid} this
54171 * @param {Number} columnIndex
54172 * @param {Roo.EventObject} e
54174 "headerdblclick" : true,
54176 * @event rowcontextmenu
54177 * Fires when a row is right clicked
54178 * @param {Grid} this
54179 * @param {Number} rowIndex
54180 * @param {Roo.EventObject} e
54182 "rowcontextmenu" : true,
54184 * @event cellcontextmenu
54185 * Fires when a cell is right clicked
54186 * @param {Grid} this
54187 * @param {Number} rowIndex
54188 * @param {Number} cellIndex
54189 * @param {Roo.EventObject} e
54191 "cellcontextmenu" : true,
54193 * @event headercontextmenu
54194 * Fires when a header is right clicked
54195 * @param {Grid} this
54196 * @param {Number} columnIndex
54197 * @param {Roo.EventObject} e
54199 "headercontextmenu" : true,
54201 * @event bodyscroll
54202 * Fires when the body element is scrolled
54203 * @param {Number} scrollLeft
54204 * @param {Number} scrollTop
54206 "bodyscroll" : true,
54208 * @event columnresize
54209 * Fires when the user resizes a column
54210 * @param {Number} columnIndex
54211 * @param {Number} newSize
54213 "columnresize" : true,
54215 * @event columnmove
54216 * Fires when the user moves a column
54217 * @param {Number} oldIndex
54218 * @param {Number} newIndex
54220 "columnmove" : true,
54223 * Fires when row(s) start being dragged
54224 * @param {Grid} this
54225 * @param {Roo.GridDD} dd The drag drop object
54226 * @param {event} e The raw browser event
54228 "startdrag" : true,
54231 * Fires when a drag operation is complete
54232 * @param {Grid} this
54233 * @param {Roo.GridDD} dd The drag drop object
54234 * @param {event} e The raw browser event
54239 * Fires when dragged row(s) are dropped on a valid DD target
54240 * @param {Grid} this
54241 * @param {Roo.GridDD} dd The drag drop object
54242 * @param {String} targetId The target drag drop object
54243 * @param {event} e The raw browser event
54248 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54249 * @param {Grid} this
54250 * @param {Roo.GridDD} dd The drag drop object
54251 * @param {String} targetId The target drag drop object
54252 * @param {event} e The raw browser event
54257 * Fires when the dragged row(s) first cross another DD target while being dragged
54258 * @param {Grid} this
54259 * @param {Roo.GridDD} dd The drag drop object
54260 * @param {String} targetId The target drag drop object
54261 * @param {event} e The raw browser event
54263 "dragenter" : true,
54266 * Fires when the dragged row(s) leave another DD target while being dragged
54267 * @param {Grid} this
54268 * @param {Roo.GridDD} dd The drag drop object
54269 * @param {String} targetId The target drag drop object
54270 * @param {event} e The raw browser event
54275 * Fires when a row is rendered, so you can change add a style to it.
54276 * @param {GridView} gridview The grid view
54277 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54283 * Fires when the grid is rendered
54284 * @param {Grid} grid
54289 Roo.grid.Grid.superclass.constructor.call(this);
54291 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54294 * @cfg {String} ddGroup - drag drop group.
54298 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54300 minColumnWidth : 25,
54303 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54304 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54305 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54307 autoSizeColumns : false,
54310 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54312 autoSizeHeaders : true,
54315 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54317 monitorWindowResize : true,
54320 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54321 * rows measured to get a columns size. Default is 0 (all rows).
54323 maxRowsToMeasure : 0,
54326 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54328 trackMouseOver : true,
54331 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54335 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54337 enableDragDrop : false,
54340 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54342 enableColumnMove : true,
54345 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54347 enableColumnHide : true,
54350 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54352 enableRowHeightSync : false,
54355 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54360 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54362 autoHeight : false,
54365 * @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.
54367 autoExpandColumn : false,
54370 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54373 autoExpandMin : 50,
54376 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54378 autoExpandMax : 1000,
54381 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54386 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54390 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54400 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54401 * of a fixed width. Default is false.
54404 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54407 * Called once after all setup has been completed and the grid is ready to be rendered.
54408 * @return {Roo.grid.Grid} this
54410 render : function()
54412 var c = this.container;
54413 // try to detect autoHeight/width mode
54414 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54415 this.autoHeight = true;
54417 var view = this.getView();
54420 c.on("click", this.onClick, this);
54421 c.on("dblclick", this.onDblClick, this);
54422 c.on("contextmenu", this.onContextMenu, this);
54423 c.on("keydown", this.onKeyDown, this);
54425 c.on("touchstart", this.onTouchStart, this);
54428 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54430 this.getSelectionModel().init(this);
54435 this.loadMask = new Roo.LoadMask(this.container,
54436 Roo.apply({store:this.dataSource}, this.loadMask));
54440 if (this.toolbar && this.toolbar.xtype) {
54441 this.toolbar.container = this.getView().getHeaderPanel(true);
54442 this.toolbar = new Roo.Toolbar(this.toolbar);
54444 if (this.footer && this.footer.xtype) {
54445 this.footer.dataSource = this.getDataSource();
54446 this.footer.container = this.getView().getFooterPanel(true);
54447 this.footer = Roo.factory(this.footer, Roo);
54449 if (this.dropTarget && this.dropTarget.xtype) {
54450 delete this.dropTarget.xtype;
54451 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54455 this.rendered = true;
54456 this.fireEvent('render', this);
54461 * Reconfigures the grid to use a different Store and Column Model.
54462 * The View will be bound to the new objects and refreshed.
54463 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54464 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54466 reconfigure : function(dataSource, colModel){
54468 this.loadMask.destroy();
54469 this.loadMask = new Roo.LoadMask(this.container,
54470 Roo.apply({store:dataSource}, this.loadMask));
54472 this.view.bind(dataSource, colModel);
54473 this.dataSource = dataSource;
54474 this.colModel = colModel;
54475 this.view.refresh(true);
54479 onKeyDown : function(e){
54480 this.fireEvent("keydown", e);
54484 * Destroy this grid.
54485 * @param {Boolean} removeEl True to remove the element
54487 destroy : function(removeEl, keepListeners){
54489 this.loadMask.destroy();
54491 var c = this.container;
54492 c.removeAllListeners();
54493 this.view.destroy();
54494 this.colModel.purgeListeners();
54495 if(!keepListeners){
54496 this.purgeListeners();
54499 if(removeEl === true){
54505 processEvent : function(name, e){
54506 // does this fire select???
54507 //Roo.log('grid:processEvent ' + name);
54509 if (name != 'touchstart' ) {
54510 this.fireEvent(name, e);
54513 var t = e.getTarget();
54515 var header = v.findHeaderIndex(t);
54516 if(header !== false){
54517 var ename = name == 'touchstart' ? 'click' : name;
54519 this.fireEvent("header" + ename, this, header, e);
54521 var row = v.findRowIndex(t);
54522 var cell = v.findCellIndex(t);
54523 if (name == 'touchstart') {
54524 // first touch is always a click.
54525 // hopefull this happens after selection is updated.?
54528 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54529 var cs = this.selModel.getSelectedCell();
54530 if (row == cs[0] && cell == cs[1]){
54534 if (typeof(this.selModel.getSelections) != 'undefined') {
54535 var cs = this.selModel.getSelections();
54536 var ds = this.dataSource;
54537 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54548 this.fireEvent("row" + name, this, row, e);
54549 if(cell !== false){
54550 this.fireEvent("cell" + name, this, row, cell, e);
54557 onClick : function(e){
54558 this.processEvent("click", e);
54561 onTouchStart : function(e){
54562 this.processEvent("touchstart", e);
54566 onContextMenu : function(e, t){
54567 this.processEvent("contextmenu", e);
54571 onDblClick : function(e){
54572 this.processEvent("dblclick", e);
54576 walkCells : function(row, col, step, fn, scope){
54577 var cm = this.colModel, clen = cm.getColumnCount();
54578 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54590 if(fn.call(scope || this, row, col, cm) === true){
54608 if(fn.call(scope || this, row, col, cm) === true){
54620 getSelections : function(){
54621 return this.selModel.getSelections();
54625 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54626 * but if manual update is required this method will initiate it.
54628 autoSize : function(){
54630 this.view.layout();
54631 if(this.view.adjustForScroll){
54632 this.view.adjustForScroll();
54638 * Returns the grid's underlying element.
54639 * @return {Element} The element
54641 getGridEl : function(){
54642 return this.container;
54645 // private for compatibility, overridden by editor grid
54646 stopEditing : function(){},
54649 * Returns the grid's SelectionModel.
54650 * @return {SelectionModel}
54652 getSelectionModel : function(){
54653 if(!this.selModel){
54654 this.selModel = new Roo.grid.RowSelectionModel();
54656 return this.selModel;
54660 * Returns the grid's DataSource.
54661 * @return {DataSource}
54663 getDataSource : function(){
54664 return this.dataSource;
54668 * Returns the grid's ColumnModel.
54669 * @return {ColumnModel}
54671 getColumnModel : function(){
54672 return this.colModel;
54676 * Returns the grid's GridView object.
54677 * @return {GridView}
54679 getView : function(){
54681 this.view = new Roo.grid.GridView(this.viewConfig);
54686 * Called to get grid's drag proxy text, by default returns this.ddText.
54689 getDragDropText : function(){
54690 var count = this.selModel.getCount();
54691 return String.format(this.ddText, count, count == 1 ? '' : 's');
54695 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54696 * %0 is replaced with the number of selected rows.
54699 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54701 * Ext JS Library 1.1.1
54702 * Copyright(c) 2006-2007, Ext JS, LLC.
54704 * Originally Released Under LGPL - original licence link has changed is not relivant.
54707 * <script type="text/javascript">
54710 Roo.grid.AbstractGridView = function(){
54714 "beforerowremoved" : true,
54715 "beforerowsinserted" : true,
54716 "beforerefresh" : true,
54717 "rowremoved" : true,
54718 "rowsinserted" : true,
54719 "rowupdated" : true,
54722 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54725 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54726 rowClass : "x-grid-row",
54727 cellClass : "x-grid-cell",
54728 tdClass : "x-grid-td",
54729 hdClass : "x-grid-hd",
54730 splitClass : "x-grid-hd-split",
54732 init: function(grid){
54734 var cid = this.grid.getGridEl().id;
54735 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54736 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54737 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54738 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54741 getColumnRenderers : function(){
54742 var renderers = [];
54743 var cm = this.grid.colModel;
54744 var colCount = cm.getColumnCount();
54745 for(var i = 0; i < colCount; i++){
54746 renderers[i] = cm.getRenderer(i);
54751 getColumnIds : function(){
54753 var cm = this.grid.colModel;
54754 var colCount = cm.getColumnCount();
54755 for(var i = 0; i < colCount; i++){
54756 ids[i] = cm.getColumnId(i);
54761 getDataIndexes : function(){
54762 if(!this.indexMap){
54763 this.indexMap = this.buildIndexMap();
54765 return this.indexMap.colToData;
54768 getColumnIndexByDataIndex : function(dataIndex){
54769 if(!this.indexMap){
54770 this.indexMap = this.buildIndexMap();
54772 return this.indexMap.dataToCol[dataIndex];
54776 * Set a css style for a column dynamically.
54777 * @param {Number} colIndex The index of the column
54778 * @param {String} name The css property name
54779 * @param {String} value The css value
54781 setCSSStyle : function(colIndex, name, value){
54782 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54783 Roo.util.CSS.updateRule(selector, name, value);
54786 generateRules : function(cm){
54787 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54788 Roo.util.CSS.removeStyleSheet(rulesId);
54789 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54790 var cid = cm.getColumnId(i);
54791 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54792 this.tdSelector, cid, " {\n}\n",
54793 this.hdSelector, cid, " {\n}\n",
54794 this.splitSelector, cid, " {\n}\n");
54796 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54800 * Ext JS Library 1.1.1
54801 * Copyright(c) 2006-2007, Ext JS, LLC.
54803 * Originally Released Under LGPL - original licence link has changed is not relivant.
54806 * <script type="text/javascript">
54810 // This is a support class used internally by the Grid components
54811 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54813 this.view = grid.getView();
54814 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54815 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54817 this.setHandleElId(Roo.id(hd));
54818 this.setOuterHandleElId(Roo.id(hd2));
54820 this.scroll = false;
54822 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54824 getDragData : function(e){
54825 var t = Roo.lib.Event.getTarget(e);
54826 var h = this.view.findHeaderCell(t);
54828 return {ddel: h.firstChild, header:h};
54833 onInitDrag : function(e){
54834 this.view.headersDisabled = true;
54835 var clone = this.dragData.ddel.cloneNode(true);
54836 clone.id = Roo.id();
54837 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54838 this.proxy.update(clone);
54842 afterValidDrop : function(){
54844 setTimeout(function(){
54845 v.headersDisabled = false;
54849 afterInvalidDrop : function(){
54851 setTimeout(function(){
54852 v.headersDisabled = false;
54858 * Ext JS Library 1.1.1
54859 * Copyright(c) 2006-2007, Ext JS, LLC.
54861 * Originally Released Under LGPL - original licence link has changed is not relivant.
54864 * <script type="text/javascript">
54867 // This is a support class used internally by the Grid components
54868 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54870 this.view = grid.getView();
54871 // split the proxies so they don't interfere with mouse events
54872 this.proxyTop = Roo.DomHelper.append(document.body, {
54873 cls:"col-move-top", html:" "
54875 this.proxyBottom = Roo.DomHelper.append(document.body, {
54876 cls:"col-move-bottom", html:" "
54878 this.proxyTop.hide = this.proxyBottom.hide = function(){
54879 this.setLeftTop(-100,-100);
54880 this.setStyle("visibility", "hidden");
54882 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54883 // temporarily disabled
54884 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54885 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54887 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54888 proxyOffsets : [-4, -9],
54889 fly: Roo.Element.fly,
54891 getTargetFromEvent : function(e){
54892 var t = Roo.lib.Event.getTarget(e);
54893 var cindex = this.view.findCellIndex(t);
54894 if(cindex !== false){
54895 return this.view.getHeaderCell(cindex);
54900 nextVisible : function(h){
54901 var v = this.view, cm = this.grid.colModel;
54904 if(!cm.isHidden(v.getCellIndex(h))){
54912 prevVisible : function(h){
54913 var v = this.view, cm = this.grid.colModel;
54916 if(!cm.isHidden(v.getCellIndex(h))){
54924 positionIndicator : function(h, n, e){
54925 var x = Roo.lib.Event.getPageX(e);
54926 var r = Roo.lib.Dom.getRegion(n.firstChild);
54927 var px, pt, py = r.top + this.proxyOffsets[1];
54928 if((r.right - x) <= (r.right-r.left)/2){
54929 px = r.right+this.view.borderWidth;
54935 var oldIndex = this.view.getCellIndex(h);
54936 var newIndex = this.view.getCellIndex(n);
54938 if(this.grid.colModel.isFixed(newIndex)){
54942 var locked = this.grid.colModel.isLocked(newIndex);
54947 if(oldIndex < newIndex){
54950 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54953 px += this.proxyOffsets[0];
54954 this.proxyTop.setLeftTop(px, py);
54955 this.proxyTop.show();
54956 if(!this.bottomOffset){
54957 this.bottomOffset = this.view.mainHd.getHeight();
54959 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54960 this.proxyBottom.show();
54964 onNodeEnter : function(n, dd, e, data){
54965 if(data.header != n){
54966 this.positionIndicator(data.header, n, e);
54970 onNodeOver : function(n, dd, e, data){
54971 var result = false;
54972 if(data.header != n){
54973 result = this.positionIndicator(data.header, n, e);
54976 this.proxyTop.hide();
54977 this.proxyBottom.hide();
54979 return result ? this.dropAllowed : this.dropNotAllowed;
54982 onNodeOut : function(n, dd, e, data){
54983 this.proxyTop.hide();
54984 this.proxyBottom.hide();
54987 onNodeDrop : function(n, dd, e, data){
54988 var h = data.header;
54990 var cm = this.grid.colModel;
54991 var x = Roo.lib.Event.getPageX(e);
54992 var r = Roo.lib.Dom.getRegion(n.firstChild);
54993 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
54994 var oldIndex = this.view.getCellIndex(h);
54995 var newIndex = this.view.getCellIndex(n);
54996 var locked = cm.isLocked(newIndex);
55000 if(oldIndex < newIndex){
55003 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55006 cm.setLocked(oldIndex, locked, true);
55007 cm.moveColumn(oldIndex, newIndex);
55008 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55016 * Ext JS Library 1.1.1
55017 * Copyright(c) 2006-2007, Ext JS, LLC.
55019 * Originally Released Under LGPL - original licence link has changed is not relivant.
55022 * <script type="text/javascript">
55026 * @class Roo.grid.GridView
55027 * @extends Roo.util.Observable
55030 * @param {Object} config
55032 Roo.grid.GridView = function(config){
55033 Roo.grid.GridView.superclass.constructor.call(this);
55036 Roo.apply(this, config);
55039 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55041 unselectable : 'unselectable="on"',
55042 unselectableCls : 'x-unselectable',
55045 rowClass : "x-grid-row",
55047 cellClass : "x-grid-col",
55049 tdClass : "x-grid-td",
55051 hdClass : "x-grid-hd",
55053 splitClass : "x-grid-split",
55055 sortClasses : ["sort-asc", "sort-desc"],
55057 enableMoveAnim : false,
55061 dh : Roo.DomHelper,
55063 fly : Roo.Element.fly,
55065 css : Roo.util.CSS,
55071 scrollIncrement : 22,
55073 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55075 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55077 bind : function(ds, cm){
55079 this.ds.un("load", this.onLoad, this);
55080 this.ds.un("datachanged", this.onDataChange, this);
55081 this.ds.un("add", this.onAdd, this);
55082 this.ds.un("remove", this.onRemove, this);
55083 this.ds.un("update", this.onUpdate, this);
55084 this.ds.un("clear", this.onClear, this);
55087 ds.on("load", this.onLoad, this);
55088 ds.on("datachanged", this.onDataChange, this);
55089 ds.on("add", this.onAdd, this);
55090 ds.on("remove", this.onRemove, this);
55091 ds.on("update", this.onUpdate, this);
55092 ds.on("clear", this.onClear, this);
55097 this.cm.un("widthchange", this.onColWidthChange, this);
55098 this.cm.un("headerchange", this.onHeaderChange, this);
55099 this.cm.un("hiddenchange", this.onHiddenChange, this);
55100 this.cm.un("columnmoved", this.onColumnMove, this);
55101 this.cm.un("columnlockchange", this.onColumnLock, this);
55104 this.generateRules(cm);
55105 cm.on("widthchange", this.onColWidthChange, this);
55106 cm.on("headerchange", this.onHeaderChange, this);
55107 cm.on("hiddenchange", this.onHiddenChange, this);
55108 cm.on("columnmoved", this.onColumnMove, this);
55109 cm.on("columnlockchange", this.onColumnLock, this);
55114 init: function(grid){
55115 Roo.grid.GridView.superclass.init.call(this, grid);
55117 this.bind(grid.dataSource, grid.colModel);
55119 grid.on("headerclick", this.handleHeaderClick, this);
55121 if(grid.trackMouseOver){
55122 grid.on("mouseover", this.onRowOver, this);
55123 grid.on("mouseout", this.onRowOut, this);
55125 grid.cancelTextSelection = function(){};
55126 this.gridId = grid.id;
55128 var tpls = this.templates || {};
55131 tpls.master = new Roo.Template(
55132 '<div class="x-grid" hidefocus="true">',
55133 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55134 '<div class="x-grid-topbar"></div>',
55135 '<div class="x-grid-scroller"><div></div></div>',
55136 '<div class="x-grid-locked">',
55137 '<div class="x-grid-header">{lockedHeader}</div>',
55138 '<div class="x-grid-body">{lockedBody}</div>',
55140 '<div class="x-grid-viewport">',
55141 '<div class="x-grid-header">{header}</div>',
55142 '<div class="x-grid-body">{body}</div>',
55144 '<div class="x-grid-bottombar"></div>',
55146 '<div class="x-grid-resize-proxy"> </div>',
55149 tpls.master.disableformats = true;
55153 tpls.header = new Roo.Template(
55154 '<table border="0" cellspacing="0" cellpadding="0">',
55155 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55158 tpls.header.disableformats = true;
55160 tpls.header.compile();
55163 tpls.hcell = new Roo.Template(
55164 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55165 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55168 tpls.hcell.disableFormats = true;
55170 tpls.hcell.compile();
55173 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55174 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55175 tpls.hsplit.disableFormats = true;
55177 tpls.hsplit.compile();
55180 tpls.body = new Roo.Template(
55181 '<table border="0" cellspacing="0" cellpadding="0">',
55182 "<tbody>{rows}</tbody>",
55185 tpls.body.disableFormats = true;
55187 tpls.body.compile();
55190 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55191 tpls.row.disableFormats = true;
55193 tpls.row.compile();
55196 tpls.cell = new Roo.Template(
55197 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55198 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55199 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55202 tpls.cell.disableFormats = true;
55204 tpls.cell.compile();
55206 this.templates = tpls;
55209 // remap these for backwards compat
55210 onColWidthChange : function(){
55211 this.updateColumns.apply(this, arguments);
55213 onHeaderChange : function(){
55214 this.updateHeaders.apply(this, arguments);
55216 onHiddenChange : function(){
55217 this.handleHiddenChange.apply(this, arguments);
55219 onColumnMove : function(){
55220 this.handleColumnMove.apply(this, arguments);
55222 onColumnLock : function(){
55223 this.handleLockChange.apply(this, arguments);
55226 onDataChange : function(){
55228 this.updateHeaderSortState();
55231 onClear : function(){
55235 onUpdate : function(ds, record){
55236 this.refreshRow(record);
55239 refreshRow : function(record){
55240 var ds = this.ds, index;
55241 if(typeof record == 'number'){
55243 record = ds.getAt(index);
55245 index = ds.indexOf(record);
55247 this.insertRows(ds, index, index, true);
55248 this.onRemove(ds, record, index+1, true);
55249 this.syncRowHeights(index, index);
55251 this.fireEvent("rowupdated", this, index, record);
55254 onAdd : function(ds, records, index){
55255 this.insertRows(ds, index, index + (records.length-1));
55258 onRemove : function(ds, record, index, isUpdate){
55259 if(isUpdate !== true){
55260 this.fireEvent("beforerowremoved", this, index, record);
55262 var bt = this.getBodyTable(), lt = this.getLockedTable();
55263 if(bt.rows[index]){
55264 bt.firstChild.removeChild(bt.rows[index]);
55266 if(lt.rows[index]){
55267 lt.firstChild.removeChild(lt.rows[index]);
55269 if(isUpdate !== true){
55270 this.stripeRows(index);
55271 this.syncRowHeights(index, index);
55273 this.fireEvent("rowremoved", this, index, record);
55277 onLoad : function(){
55278 this.scrollToTop();
55282 * Scrolls the grid to the top
55284 scrollToTop : function(){
55286 this.scroller.dom.scrollTop = 0;
55292 * Gets a panel in the header of the grid that can be used for toolbars etc.
55293 * After modifying the contents of this panel a call to grid.autoSize() may be
55294 * required to register any changes in size.
55295 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55296 * @return Roo.Element
55298 getHeaderPanel : function(doShow){
55300 this.headerPanel.show();
55302 return this.headerPanel;
55306 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55307 * After modifying the contents of this panel a call to grid.autoSize() may be
55308 * required to register any changes in size.
55309 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55310 * @return Roo.Element
55312 getFooterPanel : function(doShow){
55314 this.footerPanel.show();
55316 return this.footerPanel;
55319 initElements : function(){
55320 var E = Roo.Element;
55321 var el = this.grid.getGridEl().dom.firstChild;
55322 var cs = el.childNodes;
55324 this.el = new E(el);
55326 this.focusEl = new E(el.firstChild);
55327 this.focusEl.swallowEvent("click", true);
55329 this.headerPanel = new E(cs[1]);
55330 this.headerPanel.enableDisplayMode("block");
55332 this.scroller = new E(cs[2]);
55333 this.scrollSizer = new E(this.scroller.dom.firstChild);
55335 this.lockedWrap = new E(cs[3]);
55336 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55337 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55339 this.mainWrap = new E(cs[4]);
55340 this.mainHd = new E(this.mainWrap.dom.firstChild);
55341 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55343 this.footerPanel = new E(cs[5]);
55344 this.footerPanel.enableDisplayMode("block");
55346 this.resizeProxy = new E(cs[6]);
55348 this.headerSelector = String.format(
55349 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55350 this.lockedHd.id, this.mainHd.id
55353 this.splitterSelector = String.format(
55354 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55355 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55358 idToCssName : function(s)
55360 return s.replace(/[^a-z0-9]+/ig, '-');
55363 getHeaderCell : function(index){
55364 return Roo.DomQuery.select(this.headerSelector)[index];
55367 getHeaderCellMeasure : function(index){
55368 return this.getHeaderCell(index).firstChild;
55371 getHeaderCellText : function(index){
55372 return this.getHeaderCell(index).firstChild.firstChild;
55375 getLockedTable : function(){
55376 return this.lockedBody.dom.firstChild;
55379 getBodyTable : function(){
55380 return this.mainBody.dom.firstChild;
55383 getLockedRow : function(index){
55384 return this.getLockedTable().rows[index];
55387 getRow : function(index){
55388 return this.getBodyTable().rows[index];
55391 getRowComposite : function(index){
55393 this.rowEl = new Roo.CompositeElementLite();
55395 var els = [], lrow, mrow;
55396 if(lrow = this.getLockedRow(index)){
55399 if(mrow = this.getRow(index)){
55402 this.rowEl.elements = els;
55406 * Gets the 'td' of the cell
55408 * @param {Integer} rowIndex row to select
55409 * @param {Integer} colIndex column to select
55413 getCell : function(rowIndex, colIndex){
55414 var locked = this.cm.getLockedCount();
55416 if(colIndex < locked){
55417 source = this.lockedBody.dom.firstChild;
55419 source = this.mainBody.dom.firstChild;
55420 colIndex -= locked;
55422 return source.rows[rowIndex].childNodes[colIndex];
55425 getCellText : function(rowIndex, colIndex){
55426 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55429 getCellBox : function(cell){
55430 var b = this.fly(cell).getBox();
55431 if(Roo.isOpera){ // opera fails to report the Y
55432 b.y = cell.offsetTop + this.mainBody.getY();
55437 getCellIndex : function(cell){
55438 var id = String(cell.className).match(this.cellRE);
55440 return parseInt(id[1], 10);
55445 findHeaderIndex : function(n){
55446 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55447 return r ? this.getCellIndex(r) : false;
55450 findHeaderCell : function(n){
55451 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55452 return r ? r : false;
55455 findRowIndex : function(n){
55459 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55460 return r ? r.rowIndex : false;
55463 findCellIndex : function(node){
55464 var stop = this.el.dom;
55465 while(node && node != stop){
55466 if(this.findRE.test(node.className)){
55467 return this.getCellIndex(node);
55469 node = node.parentNode;
55474 getColumnId : function(index){
55475 return this.cm.getColumnId(index);
55478 getSplitters : function()
55480 if(this.splitterSelector){
55481 return Roo.DomQuery.select(this.splitterSelector);
55487 getSplitter : function(index){
55488 return this.getSplitters()[index];
55491 onRowOver : function(e, t){
55493 if((row = this.findRowIndex(t)) !== false){
55494 this.getRowComposite(row).addClass("x-grid-row-over");
55498 onRowOut : function(e, t){
55500 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55501 this.getRowComposite(row).removeClass("x-grid-row-over");
55505 renderHeaders : function(){
55507 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55508 var cb = [], lb = [], sb = [], lsb = [], p = {};
55509 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55510 p.cellId = "x-grid-hd-0-" + i;
55511 p.splitId = "x-grid-csplit-0-" + i;
55512 p.id = cm.getColumnId(i);
55513 p.value = cm.getColumnHeader(i) || "";
55514 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55515 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55516 if(!cm.isLocked(i)){
55517 cb[cb.length] = ct.apply(p);
55518 sb[sb.length] = st.apply(p);
55520 lb[lb.length] = ct.apply(p);
55521 lsb[lsb.length] = st.apply(p);
55524 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55525 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55528 updateHeaders : function(){
55529 var html = this.renderHeaders();
55530 this.lockedHd.update(html[0]);
55531 this.mainHd.update(html[1]);
55535 * Focuses the specified row.
55536 * @param {Number} row The row index
55538 focusRow : function(row)
55540 //Roo.log('GridView.focusRow');
55541 var x = this.scroller.dom.scrollLeft;
55542 this.focusCell(row, 0, false);
55543 this.scroller.dom.scrollLeft = x;
55547 * Focuses the specified cell.
55548 * @param {Number} row The row index
55549 * @param {Number} col The column index
55550 * @param {Boolean} hscroll false to disable horizontal scrolling
55552 focusCell : function(row, col, hscroll)
55554 //Roo.log('GridView.focusCell');
55555 var el = this.ensureVisible(row, col, hscroll);
55556 this.focusEl.alignTo(el, "tl-tl");
55558 this.focusEl.focus();
55560 this.focusEl.focus.defer(1, this.focusEl);
55565 * Scrolls the specified cell into view
55566 * @param {Number} row The row index
55567 * @param {Number} col The column index
55568 * @param {Boolean} hscroll false to disable horizontal scrolling
55570 ensureVisible : function(row, col, hscroll)
55572 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55573 //return null; //disable for testing.
55574 if(typeof row != "number"){
55575 row = row.rowIndex;
55577 if(row < 0 && row >= this.ds.getCount()){
55580 col = (col !== undefined ? col : 0);
55581 var cm = this.grid.colModel;
55582 while(cm.isHidden(col)){
55586 var el = this.getCell(row, col);
55590 var c = this.scroller.dom;
55592 var ctop = parseInt(el.offsetTop, 10);
55593 var cleft = parseInt(el.offsetLeft, 10);
55594 var cbot = ctop + el.offsetHeight;
55595 var cright = cleft + el.offsetWidth;
55597 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55598 var stop = parseInt(c.scrollTop, 10);
55599 var sleft = parseInt(c.scrollLeft, 10);
55600 var sbot = stop + ch;
55601 var sright = sleft + c.clientWidth;
55603 Roo.log('GridView.ensureVisible:' +
55605 ' c.clientHeight:' + c.clientHeight +
55606 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55614 c.scrollTop = ctop;
55615 //Roo.log("set scrolltop to ctop DISABLE?");
55616 }else if(cbot > sbot){
55617 //Roo.log("set scrolltop to cbot-ch");
55618 c.scrollTop = cbot-ch;
55621 if(hscroll !== false){
55623 c.scrollLeft = cleft;
55624 }else if(cright > sright){
55625 c.scrollLeft = cright-c.clientWidth;
55632 updateColumns : function(){
55633 this.grid.stopEditing();
55634 var cm = this.grid.colModel, colIds = this.getColumnIds();
55635 //var totalWidth = cm.getTotalWidth();
55637 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55638 //if(cm.isHidden(i)) continue;
55639 var w = cm.getColumnWidth(i);
55640 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55641 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55643 this.updateSplitters();
55646 generateRules : function(cm){
55647 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55648 Roo.util.CSS.removeStyleSheet(rulesId);
55649 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55650 var cid = cm.getColumnId(i);
55652 if(cm.config[i].align){
55653 align = 'text-align:'+cm.config[i].align+';';
55656 if(cm.isHidden(i)){
55657 hidden = 'display:none;';
55659 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55661 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55662 this.hdSelector, cid, " {\n", align, width, "}\n",
55663 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55664 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55666 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55669 updateSplitters : function(){
55670 var cm = this.cm, s = this.getSplitters();
55671 if(s){ // splitters not created yet
55672 var pos = 0, locked = true;
55673 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55674 if(cm.isHidden(i)) {
55677 var w = cm.getColumnWidth(i); // make sure it's a number
55678 if(!cm.isLocked(i) && locked){
55683 s[i].style.left = (pos-this.splitOffset) + "px";
55688 handleHiddenChange : function(colModel, colIndex, hidden){
55690 this.hideColumn(colIndex);
55692 this.unhideColumn(colIndex);
55696 hideColumn : function(colIndex){
55697 var cid = this.getColumnId(colIndex);
55698 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55699 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55701 this.updateHeaders();
55703 this.updateSplitters();
55707 unhideColumn : function(colIndex){
55708 var cid = this.getColumnId(colIndex);
55709 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55710 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55713 this.updateHeaders();
55715 this.updateSplitters();
55719 insertRows : function(dm, firstRow, lastRow, isUpdate){
55720 if(firstRow == 0 && lastRow == dm.getCount()-1){
55724 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55726 var s = this.getScrollState();
55727 var markup = this.renderRows(firstRow, lastRow);
55728 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55729 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55730 this.restoreScroll(s);
55732 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55733 this.syncRowHeights(firstRow, lastRow);
55734 this.stripeRows(firstRow);
55740 bufferRows : function(markup, target, index){
55741 var before = null, trows = target.rows, tbody = target.tBodies[0];
55742 if(index < trows.length){
55743 before = trows[index];
55745 var b = document.createElement("div");
55746 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55747 var rows = b.firstChild.rows;
55748 for(var i = 0, len = rows.length; i < len; i++){
55750 tbody.insertBefore(rows[0], before);
55752 tbody.appendChild(rows[0]);
55759 deleteRows : function(dm, firstRow, lastRow){
55760 if(dm.getRowCount()<1){
55761 this.fireEvent("beforerefresh", this);
55762 this.mainBody.update("");
55763 this.lockedBody.update("");
55764 this.fireEvent("refresh", this);
55766 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55767 var bt = this.getBodyTable();
55768 var tbody = bt.firstChild;
55769 var rows = bt.rows;
55770 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55771 tbody.removeChild(rows[firstRow]);
55773 this.stripeRows(firstRow);
55774 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55778 updateRows : function(dataSource, firstRow, lastRow){
55779 var s = this.getScrollState();
55781 this.restoreScroll(s);
55784 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55788 this.updateHeaderSortState();
55791 getScrollState : function(){
55793 var sb = this.scroller.dom;
55794 return {left: sb.scrollLeft, top: sb.scrollTop};
55797 stripeRows : function(startRow){
55798 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55801 startRow = startRow || 0;
55802 var rows = this.getBodyTable().rows;
55803 var lrows = this.getLockedTable().rows;
55804 var cls = ' x-grid-row-alt ';
55805 for(var i = startRow, len = rows.length; i < len; i++){
55806 var row = rows[i], lrow = lrows[i];
55807 var isAlt = ((i+1) % 2 == 0);
55808 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55809 if(isAlt == hasAlt){
55813 row.className += " x-grid-row-alt";
55815 row.className = row.className.replace("x-grid-row-alt", "");
55818 lrow.className = row.className;
55823 restoreScroll : function(state){
55824 //Roo.log('GridView.restoreScroll');
55825 var sb = this.scroller.dom;
55826 sb.scrollLeft = state.left;
55827 sb.scrollTop = state.top;
55831 syncScroll : function(){
55832 //Roo.log('GridView.syncScroll');
55833 var sb = this.scroller.dom;
55834 var sh = this.mainHd.dom;
55835 var bs = this.mainBody.dom;
55836 var lv = this.lockedBody.dom;
55837 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55838 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55841 handleScroll : function(e){
55843 var sb = this.scroller.dom;
55844 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55848 handleWheel : function(e){
55849 var d = e.getWheelDelta();
55850 this.scroller.dom.scrollTop -= d*22;
55851 // set this here to prevent jumpy scrolling on large tables
55852 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55856 renderRows : function(startRow, endRow){
55857 // pull in all the crap needed to render rows
55858 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55859 var colCount = cm.getColumnCount();
55861 if(ds.getCount() < 1){
55865 // build a map for all the columns
55867 for(var i = 0; i < colCount; i++){
55868 var name = cm.getDataIndex(i);
55870 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55871 renderer : cm.getRenderer(i),
55872 id : cm.getColumnId(i),
55873 locked : cm.isLocked(i),
55874 has_editor : cm.isCellEditable(i)
55878 startRow = startRow || 0;
55879 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55881 // records to render
55882 var rs = ds.getRange(startRow, endRow);
55884 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55887 // As much as I hate to duplicate code, this was branched because FireFox really hates
55888 // [].join("") on strings. The performance difference was substantial enough to
55889 // branch this function
55890 doRender : Roo.isGecko ?
55891 function(cs, rs, ds, startRow, colCount, stripe){
55892 var ts = this.templates, ct = ts.cell, rt = ts.row;
55894 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55896 var hasListener = this.grid.hasListener('rowclass');
55898 for(var j = 0, len = rs.length; j < len; j++){
55899 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55900 for(var i = 0; i < colCount; i++){
55902 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55904 p.css = p.attr = "";
55905 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55906 if(p.value == undefined || p.value === "") {
55907 p.value = " ";
55910 p.css += ' x-grid-editable-cell';
55912 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55913 p.css += ' x-grid-dirty-cell';
55915 var markup = ct.apply(p);
55923 if(stripe && ((rowIndex+1) % 2 == 0)){
55924 alt.push("x-grid-row-alt")
55927 alt.push( " x-grid-dirty-row");
55930 if(this.getRowClass){
55931 alt.push(this.getRowClass(r, rowIndex));
55937 rowIndex : rowIndex,
55940 this.grid.fireEvent('rowclass', this, rowcfg);
55941 alt.push(rowcfg.rowClass);
55943 rp.alt = alt.join(" ");
55944 lbuf+= rt.apply(rp);
55946 buf+= rt.apply(rp);
55948 return [lbuf, buf];
55950 function(cs, rs, ds, startRow, colCount, stripe){
55951 var ts = this.templates, ct = ts.cell, rt = ts.row;
55953 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55954 var hasListener = this.grid.hasListener('rowclass');
55957 for(var j = 0, len = rs.length; j < len; j++){
55958 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55959 for(var i = 0; i < colCount; i++){
55961 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55963 p.css = p.attr = "";
55964 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55965 if(p.value == undefined || p.value === "") {
55966 p.value = " ";
55970 p.css += ' x-grid-editable-cell';
55972 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55973 p.css += ' x-grid-dirty-cell'
55976 var markup = ct.apply(p);
55978 cb[cb.length] = markup;
55980 lcb[lcb.length] = markup;
55984 if(stripe && ((rowIndex+1) % 2 == 0)){
55985 alt.push( "x-grid-row-alt");
55988 alt.push(" x-grid-dirty-row");
55991 if(this.getRowClass){
55992 alt.push( this.getRowClass(r, rowIndex));
55998 rowIndex : rowIndex,
56001 this.grid.fireEvent('rowclass', this, rowcfg);
56002 alt.push(rowcfg.rowClass);
56005 rp.alt = alt.join(" ");
56006 rp.cells = lcb.join("");
56007 lbuf[lbuf.length] = rt.apply(rp);
56008 rp.cells = cb.join("");
56009 buf[buf.length] = rt.apply(rp);
56011 return [lbuf.join(""), buf.join("")];
56014 renderBody : function(){
56015 var markup = this.renderRows();
56016 var bt = this.templates.body;
56017 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56021 * Refreshes the grid
56022 * @param {Boolean} headersToo
56024 refresh : function(headersToo){
56025 this.fireEvent("beforerefresh", this);
56026 this.grid.stopEditing();
56027 var result = this.renderBody();
56028 this.lockedBody.update(result[0]);
56029 this.mainBody.update(result[1]);
56030 if(headersToo === true){
56031 this.updateHeaders();
56032 this.updateColumns();
56033 this.updateSplitters();
56034 this.updateHeaderSortState();
56036 this.syncRowHeights();
56038 this.fireEvent("refresh", this);
56041 handleColumnMove : function(cm, oldIndex, newIndex){
56042 this.indexMap = null;
56043 var s = this.getScrollState();
56044 this.refresh(true);
56045 this.restoreScroll(s);
56046 this.afterMove(newIndex);
56049 afterMove : function(colIndex){
56050 if(this.enableMoveAnim && Roo.enableFx){
56051 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56053 // if multisort - fix sortOrder, and reload..
56054 if (this.grid.dataSource.multiSort) {
56055 // the we can call sort again..
56056 var dm = this.grid.dataSource;
56057 var cm = this.grid.colModel;
56059 for(var i = 0; i < cm.config.length; i++ ) {
56061 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56062 continue; // dont' bother, it's not in sort list or being set.
56065 so.push(cm.config[i].dataIndex);
56068 dm.load(dm.lastOptions);
56075 updateCell : function(dm, rowIndex, dataIndex){
56076 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56077 if(typeof colIndex == "undefined"){ // not present in grid
56080 var cm = this.grid.colModel;
56081 var cell = this.getCell(rowIndex, colIndex);
56082 var cellText = this.getCellText(rowIndex, colIndex);
56085 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56086 id : cm.getColumnId(colIndex),
56087 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56089 var renderer = cm.getRenderer(colIndex);
56090 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56091 if(typeof val == "undefined" || val === "") {
56094 cellText.innerHTML = val;
56095 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56096 this.syncRowHeights(rowIndex, rowIndex);
56099 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56101 if(this.grid.autoSizeHeaders){
56102 var h = this.getHeaderCellMeasure(colIndex);
56103 maxWidth = Math.max(maxWidth, h.scrollWidth);
56106 if(this.cm.isLocked(colIndex)){
56107 tb = this.getLockedTable();
56110 tb = this.getBodyTable();
56111 index = colIndex - this.cm.getLockedCount();
56114 var rows = tb.rows;
56115 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56116 for(var i = 0; i < stopIndex; i++){
56117 var cell = rows[i].childNodes[index].firstChild;
56118 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56121 return maxWidth + /*margin for error in IE*/ 5;
56124 * Autofit a column to its content.
56125 * @param {Number} colIndex
56126 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56128 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56129 if(this.cm.isHidden(colIndex)){
56130 return; // can't calc a hidden column
56133 var cid = this.cm.getColumnId(colIndex);
56134 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56135 if(this.grid.autoSizeHeaders){
56136 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56139 var newWidth = this.calcColumnWidth(colIndex);
56140 this.cm.setColumnWidth(colIndex,
56141 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56142 if(!suppressEvent){
56143 this.grid.fireEvent("columnresize", colIndex, newWidth);
56148 * Autofits all columns to their content and then expands to fit any extra space in the grid
56150 autoSizeColumns : function(){
56151 var cm = this.grid.colModel;
56152 var colCount = cm.getColumnCount();
56153 for(var i = 0; i < colCount; i++){
56154 this.autoSizeColumn(i, true, true);
56156 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56159 this.updateColumns();
56165 * Autofits all columns to the grid's width proportionate with their current size
56166 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56168 fitColumns : function(reserveScrollSpace){
56169 var cm = this.grid.colModel;
56170 var colCount = cm.getColumnCount();
56174 for (i = 0; i < colCount; i++){
56175 if(!cm.isHidden(i) && !cm.isFixed(i)){
56176 w = cm.getColumnWidth(i);
56182 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56183 if(reserveScrollSpace){
56186 var frac = (avail - cm.getTotalWidth())/width;
56187 while (cols.length){
56190 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56192 this.updateColumns();
56196 onRowSelect : function(rowIndex){
56197 var row = this.getRowComposite(rowIndex);
56198 row.addClass("x-grid-row-selected");
56201 onRowDeselect : function(rowIndex){
56202 var row = this.getRowComposite(rowIndex);
56203 row.removeClass("x-grid-row-selected");
56206 onCellSelect : function(row, col){
56207 var cell = this.getCell(row, col);
56209 Roo.fly(cell).addClass("x-grid-cell-selected");
56213 onCellDeselect : function(row, col){
56214 var cell = this.getCell(row, col);
56216 Roo.fly(cell).removeClass("x-grid-cell-selected");
56220 updateHeaderSortState : function(){
56222 // sort state can be single { field: xxx, direction : yyy}
56223 // or { xxx=>ASC , yyy : DESC ..... }
56226 if (!this.ds.multiSort) {
56227 var state = this.ds.getSortState();
56231 mstate[state.field] = state.direction;
56232 // FIXME... - this is not used here.. but might be elsewhere..
56233 this.sortState = state;
56236 mstate = this.ds.sortToggle;
56238 //remove existing sort classes..
56240 var sc = this.sortClasses;
56241 var hds = this.el.select(this.headerSelector).removeClass(sc);
56243 for(var f in mstate) {
56245 var sortColumn = this.cm.findColumnIndex(f);
56247 if(sortColumn != -1){
56248 var sortDir = mstate[f];
56249 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56258 handleHeaderClick : function(g, index,e){
56260 Roo.log("header click");
56263 // touch events on header are handled by context
56264 this.handleHdCtx(g,index,e);
56269 if(this.headersDisabled){
56272 var dm = g.dataSource, cm = g.colModel;
56273 if(!cm.isSortable(index)){
56278 if (dm.multiSort) {
56279 // update the sortOrder
56281 for(var i = 0; i < cm.config.length; i++ ) {
56283 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56284 continue; // dont' bother, it's not in sort list or being set.
56287 so.push(cm.config[i].dataIndex);
56293 dm.sort(cm.getDataIndex(index));
56297 destroy : function(){
56299 this.colMenu.removeAll();
56300 Roo.menu.MenuMgr.unregister(this.colMenu);
56301 this.colMenu.getEl().remove();
56302 delete this.colMenu;
56305 this.hmenu.removeAll();
56306 Roo.menu.MenuMgr.unregister(this.hmenu);
56307 this.hmenu.getEl().remove();
56310 if(this.grid.enableColumnMove){
56311 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56313 for(var dd in dds){
56314 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56315 var elid = dds[dd].dragElId;
56317 Roo.get(elid).remove();
56318 } else if(dds[dd].config.isTarget){
56319 dds[dd].proxyTop.remove();
56320 dds[dd].proxyBottom.remove();
56323 if(Roo.dd.DDM.locationCache[dd]){
56324 delete Roo.dd.DDM.locationCache[dd];
56327 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56330 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56331 this.bind(null, null);
56332 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56335 handleLockChange : function(){
56336 this.refresh(true);
56339 onDenyColumnLock : function(){
56343 onDenyColumnHide : function(){
56347 handleHdMenuClick : function(item){
56348 var index = this.hdCtxIndex;
56349 var cm = this.cm, ds = this.ds;
56352 ds.sort(cm.getDataIndex(index), "ASC");
56355 ds.sort(cm.getDataIndex(index), "DESC");
56358 var lc = cm.getLockedCount();
56359 if(cm.getColumnCount(true) <= lc+1){
56360 this.onDenyColumnLock();
56364 cm.setLocked(index, true, true);
56365 cm.moveColumn(index, lc);
56366 this.grid.fireEvent("columnmove", index, lc);
56368 cm.setLocked(index, true);
56372 var lc = cm.getLockedCount();
56373 if((lc-1) != index){
56374 cm.setLocked(index, false, true);
56375 cm.moveColumn(index, lc-1);
56376 this.grid.fireEvent("columnmove", index, lc-1);
56378 cm.setLocked(index, false);
56381 case 'wider': // used to expand cols on touch..
56383 var cw = cm.getColumnWidth(index);
56384 cw += (item.id == 'wider' ? 1 : -1) * 50;
56385 cw = Math.max(0, cw);
56386 cw = Math.min(cw,4000);
56387 cm.setColumnWidth(index, cw);
56391 index = cm.getIndexById(item.id.substr(4));
56393 if(item.checked && cm.getColumnCount(true) <= 1){
56394 this.onDenyColumnHide();
56397 cm.setHidden(index, item.checked);
56403 beforeColMenuShow : function(){
56404 var cm = this.cm, colCount = cm.getColumnCount();
56405 this.colMenu.removeAll();
56406 for(var i = 0; i < colCount; i++){
56407 this.colMenu.add(new Roo.menu.CheckItem({
56408 id: "col-"+cm.getColumnId(i),
56409 text: cm.getColumnHeader(i),
56410 checked: !cm.isHidden(i),
56416 handleHdCtx : function(g, index, e){
56418 var hd = this.getHeaderCell(index);
56419 this.hdCtxIndex = index;
56420 var ms = this.hmenu.items, cm = this.cm;
56421 ms.get("asc").setDisabled(!cm.isSortable(index));
56422 ms.get("desc").setDisabled(!cm.isSortable(index));
56423 if(this.grid.enableColLock !== false){
56424 ms.get("lock").setDisabled(cm.isLocked(index));
56425 ms.get("unlock").setDisabled(!cm.isLocked(index));
56427 this.hmenu.show(hd, "tl-bl");
56430 handleHdOver : function(e){
56431 var hd = this.findHeaderCell(e.getTarget());
56432 if(hd && !this.headersDisabled){
56433 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56434 this.fly(hd).addClass("x-grid-hd-over");
56439 handleHdOut : function(e){
56440 var hd = this.findHeaderCell(e.getTarget());
56442 this.fly(hd).removeClass("x-grid-hd-over");
56446 handleSplitDblClick : function(e, t){
56447 var i = this.getCellIndex(t);
56448 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56449 this.autoSizeColumn(i, true);
56454 render : function(){
56457 var colCount = cm.getColumnCount();
56459 if(this.grid.monitorWindowResize === true){
56460 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56462 var header = this.renderHeaders();
56463 var body = this.templates.body.apply({rows:""});
56464 var html = this.templates.master.apply({
56467 lockedHeader: header[0],
56471 //this.updateColumns();
56473 this.grid.getGridEl().dom.innerHTML = html;
56475 this.initElements();
56477 // a kludge to fix the random scolling effect in webkit
56478 this.el.on("scroll", function() {
56479 this.el.dom.scrollTop=0; // hopefully not recursive..
56482 this.scroller.on("scroll", this.handleScroll, this);
56483 this.lockedBody.on("mousewheel", this.handleWheel, this);
56484 this.mainBody.on("mousewheel", this.handleWheel, this);
56486 this.mainHd.on("mouseover", this.handleHdOver, this);
56487 this.mainHd.on("mouseout", this.handleHdOut, this);
56488 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56489 {delegate: "."+this.splitClass});
56491 this.lockedHd.on("mouseover", this.handleHdOver, this);
56492 this.lockedHd.on("mouseout", this.handleHdOut, this);
56493 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56494 {delegate: "."+this.splitClass});
56496 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56497 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56500 this.updateSplitters();
56502 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56503 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56504 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56507 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56508 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56510 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56511 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56513 if(this.grid.enableColLock !== false){
56514 this.hmenu.add('-',
56515 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56516 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56520 this.hmenu.add('-',
56521 {id:"wider", text: this.columnsWiderText},
56522 {id:"narrow", text: this.columnsNarrowText }
56528 if(this.grid.enableColumnHide !== false){
56530 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56531 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56532 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56534 this.hmenu.add('-',
56535 {id:"columns", text: this.columnsText, menu: this.colMenu}
56538 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56540 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56543 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56544 this.dd = new Roo.grid.GridDragZone(this.grid, {
56545 ddGroup : this.grid.ddGroup || 'GridDD'
56551 for(var i = 0; i < colCount; i++){
56552 if(cm.isHidden(i)){
56553 this.hideColumn(i);
56555 if(cm.config[i].align){
56556 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56557 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56561 this.updateHeaderSortState();
56563 this.beforeInitialResize();
56566 // two part rendering gives faster view to the user
56567 this.renderPhase2.defer(1, this);
56570 renderPhase2 : function(){
56571 // render the rows now
56573 if(this.grid.autoSizeColumns){
56574 this.autoSizeColumns();
56578 beforeInitialResize : function(){
56582 onColumnSplitterMoved : function(i, w){
56583 this.userResized = true;
56584 var cm = this.grid.colModel;
56585 cm.setColumnWidth(i, w, true);
56586 var cid = cm.getColumnId(i);
56587 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56588 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56589 this.updateSplitters();
56591 this.grid.fireEvent("columnresize", i, w);
56594 syncRowHeights : function(startIndex, endIndex){
56595 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56596 startIndex = startIndex || 0;
56597 var mrows = this.getBodyTable().rows;
56598 var lrows = this.getLockedTable().rows;
56599 var len = mrows.length-1;
56600 endIndex = Math.min(endIndex || len, len);
56601 for(var i = startIndex; i <= endIndex; i++){
56602 var m = mrows[i], l = lrows[i];
56603 var h = Math.max(m.offsetHeight, l.offsetHeight);
56604 m.style.height = l.style.height = h + "px";
56609 layout : function(initialRender, is2ndPass){
56611 var auto = g.autoHeight;
56612 var scrollOffset = 16;
56613 var c = g.getGridEl(), cm = this.cm,
56614 expandCol = g.autoExpandColumn,
56616 //c.beginMeasure();
56618 if(!c.dom.offsetWidth){ // display:none?
56620 this.lockedWrap.show();
56621 this.mainWrap.show();
56626 var hasLock = this.cm.isLocked(0);
56628 var tbh = this.headerPanel.getHeight();
56629 var bbh = this.footerPanel.getHeight();
56632 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56633 var newHeight = ch + c.getBorderWidth("tb");
56635 newHeight = Math.min(g.maxHeight, newHeight);
56637 c.setHeight(newHeight);
56641 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56644 var s = this.scroller;
56646 var csize = c.getSize(true);
56648 this.el.setSize(csize.width, csize.height);
56650 this.headerPanel.setWidth(csize.width);
56651 this.footerPanel.setWidth(csize.width);
56653 var hdHeight = this.mainHd.getHeight();
56654 var vw = csize.width;
56655 var vh = csize.height - (tbh + bbh);
56659 var bt = this.getBodyTable();
56661 if(cm.getLockedCount() == cm.config.length){
56662 bt = this.getLockedTable();
56665 var ltWidth = hasLock ?
56666 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56668 var scrollHeight = bt.offsetHeight;
56669 var scrollWidth = ltWidth + bt.offsetWidth;
56670 var vscroll = false, hscroll = false;
56672 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56674 var lw = this.lockedWrap, mw = this.mainWrap;
56675 var lb = this.lockedBody, mb = this.mainBody;
56677 setTimeout(function(){
56678 var t = s.dom.offsetTop;
56679 var w = s.dom.clientWidth,
56680 h = s.dom.clientHeight;
56683 lw.setSize(ltWidth, h);
56685 mw.setLeftTop(ltWidth, t);
56686 mw.setSize(w-ltWidth, h);
56688 lb.setHeight(h-hdHeight);
56689 mb.setHeight(h-hdHeight);
56691 if(is2ndPass !== true && !gv.userResized && expandCol){
56692 // high speed resize without full column calculation
56694 var ci = cm.getIndexById(expandCol);
56696 ci = cm.findColumnIndex(expandCol);
56698 ci = Math.max(0, ci); // make sure it's got at least the first col.
56699 var expandId = cm.getColumnId(ci);
56700 var tw = cm.getTotalWidth(false);
56701 var currentWidth = cm.getColumnWidth(ci);
56702 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56703 if(currentWidth != cw){
56704 cm.setColumnWidth(ci, cw, true);
56705 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56706 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56707 gv.updateSplitters();
56708 gv.layout(false, true);
56720 onWindowResize : function(){
56721 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56727 appendFooter : function(parentEl){
56731 sortAscText : "Sort Ascending",
56732 sortDescText : "Sort Descending",
56733 lockText : "Lock Column",
56734 unlockText : "Unlock Column",
56735 columnsText : "Columns",
56737 columnsWiderText : "Wider",
56738 columnsNarrowText : "Thinner"
56742 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56743 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56744 this.proxy.el.addClass('x-grid3-col-dd');
56747 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56748 handleMouseDown : function(e){
56752 callHandleMouseDown : function(e){
56753 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56758 * Ext JS Library 1.1.1
56759 * Copyright(c) 2006-2007, Ext JS, LLC.
56761 * Originally Released Under LGPL - original licence link has changed is not relivant.
56764 * <script type="text/javascript">
56768 // This is a support class used internally by the Grid components
56769 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56771 this.view = grid.getView();
56772 this.proxy = this.view.resizeProxy;
56773 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56774 "gridSplitters" + this.grid.getGridEl().id, {
56775 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56777 this.setHandleElId(Roo.id(hd));
56778 this.setOuterHandleElId(Roo.id(hd2));
56779 this.scroll = false;
56781 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56782 fly: Roo.Element.fly,
56784 b4StartDrag : function(x, y){
56785 this.view.headersDisabled = true;
56786 this.proxy.setHeight(this.view.mainWrap.getHeight());
56787 var w = this.cm.getColumnWidth(this.cellIndex);
56788 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56789 this.resetConstraints();
56790 this.setXConstraint(minw, 1000);
56791 this.setYConstraint(0, 0);
56792 this.minX = x - minw;
56793 this.maxX = x + 1000;
56795 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56799 handleMouseDown : function(e){
56800 ev = Roo.EventObject.setEvent(e);
56801 var t = this.fly(ev.getTarget());
56802 if(t.hasClass("x-grid-split")){
56803 this.cellIndex = this.view.getCellIndex(t.dom);
56804 this.split = t.dom;
56805 this.cm = this.grid.colModel;
56806 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56807 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56812 endDrag : function(e){
56813 this.view.headersDisabled = false;
56814 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56815 var diff = endX - this.startPos;
56816 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56819 autoOffset : function(){
56820 this.setDelta(0,0);
56824 * Ext JS Library 1.1.1
56825 * Copyright(c) 2006-2007, Ext JS, LLC.
56827 * Originally Released Under LGPL - original licence link has changed is not relivant.
56830 * <script type="text/javascript">
56834 // This is a support class used internally by the Grid components
56835 Roo.grid.GridDragZone = function(grid, config){
56836 this.view = grid.getView();
56837 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56838 if(this.view.lockedBody){
56839 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56840 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56842 this.scroll = false;
56844 this.ddel = document.createElement('div');
56845 this.ddel.className = 'x-grid-dd-wrap';
56848 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56849 ddGroup : "GridDD",
56851 getDragData : function(e){
56852 var t = Roo.lib.Event.getTarget(e);
56853 var rowIndex = this.view.findRowIndex(t);
56854 var sm = this.grid.selModel;
56856 //Roo.log(rowIndex);
56858 if (sm.getSelectedCell) {
56859 // cell selection..
56860 if (!sm.getSelectedCell()) {
56863 if (rowIndex != sm.getSelectedCell()[0]) {
56869 if(rowIndex !== false){
56874 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56876 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56879 if (e.hasModifier()){
56880 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56883 Roo.log("getDragData");
56888 rowIndex: rowIndex,
56889 selections:sm.getSelections ? sm.getSelections() : (
56890 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56897 onInitDrag : function(e){
56898 var data = this.dragData;
56899 this.ddel.innerHTML = this.grid.getDragDropText();
56900 this.proxy.update(this.ddel);
56901 // fire start drag?
56904 afterRepair : function(){
56905 this.dragging = false;
56908 getRepairXY : function(e, data){
56912 onEndDrag : function(data, e){
56916 onValidDrop : function(dd, e, id){
56921 beforeInvalidDrop : function(e, id){
56926 * Ext JS Library 1.1.1
56927 * Copyright(c) 2006-2007, Ext JS, LLC.
56929 * Originally Released Under LGPL - original licence link has changed is not relivant.
56932 * <script type="text/javascript">
56937 * @class Roo.grid.ColumnModel
56938 * @extends Roo.util.Observable
56939 * This is the default implementation of a ColumnModel used by the Grid. It defines
56940 * the columns in the grid.
56943 var colModel = new Roo.grid.ColumnModel([
56944 {header: "Ticker", width: 60, sortable: true, locked: true},
56945 {header: "Company Name", width: 150, sortable: true},
56946 {header: "Market Cap.", width: 100, sortable: true},
56947 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56948 {header: "Employees", width: 100, sortable: true, resizable: false}
56953 * The config options listed for this class are options which may appear in each
56954 * individual column definition.
56955 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56957 * @param {Object} config An Array of column config objects. See this class's
56958 * config objects for details.
56960 Roo.grid.ColumnModel = function(config){
56962 * The config passed into the constructor
56964 this.config = config;
56967 // if no id, create one
56968 // if the column does not have a dataIndex mapping,
56969 // map it to the order it is in the config
56970 for(var i = 0, len = config.length; i < len; i++){
56972 if(typeof c.dataIndex == "undefined"){
56975 if(typeof c.renderer == "string"){
56976 c.renderer = Roo.util.Format[c.renderer];
56978 if(typeof c.id == "undefined"){
56981 if(c.editor && c.editor.xtype){
56982 c.editor = Roo.factory(c.editor, Roo.grid);
56984 if(c.editor && c.editor.isFormField){
56985 c.editor = new Roo.grid.GridEditor(c.editor);
56987 this.lookup[c.id] = c;
56991 * The width of columns which have no width specified (defaults to 100)
56994 this.defaultWidth = 100;
56997 * Default sortable of columns which have no sortable specified (defaults to false)
57000 this.defaultSortable = false;
57004 * @event widthchange
57005 * Fires when the width of a column changes.
57006 * @param {ColumnModel} this
57007 * @param {Number} columnIndex The column index
57008 * @param {Number} newWidth The new width
57010 "widthchange": true,
57012 * @event headerchange
57013 * Fires when the text of a header changes.
57014 * @param {ColumnModel} this
57015 * @param {Number} columnIndex The column index
57016 * @param {Number} newText The new header text
57018 "headerchange": true,
57020 * @event hiddenchange
57021 * Fires when a column is hidden or "unhidden".
57022 * @param {ColumnModel} this
57023 * @param {Number} columnIndex The column index
57024 * @param {Boolean} hidden true if hidden, false otherwise
57026 "hiddenchange": true,
57028 * @event columnmoved
57029 * Fires when a column is moved.
57030 * @param {ColumnModel} this
57031 * @param {Number} oldIndex
57032 * @param {Number} newIndex
57034 "columnmoved" : true,
57036 * @event columlockchange
57037 * Fires when a column's locked state is changed
57038 * @param {ColumnModel} this
57039 * @param {Number} colIndex
57040 * @param {Boolean} locked true if locked
57042 "columnlockchange" : true
57044 Roo.grid.ColumnModel.superclass.constructor.call(this);
57046 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57048 * @cfg {String} header The header text to display in the Grid view.
57051 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57052 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57053 * specified, the column's index is used as an index into the Record's data Array.
57056 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57057 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57060 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57061 * Defaults to the value of the {@link #defaultSortable} property.
57062 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57065 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57068 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57071 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57074 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57077 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57078 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57079 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57080 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57083 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57086 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57089 * @cfg {String} cursor (Optional)
57092 * @cfg {String} tooltip (Optional)
57095 * @cfg {Number} xs (Optional)
57098 * @cfg {Number} sm (Optional)
57101 * @cfg {Number} md (Optional)
57104 * @cfg {Number} lg (Optional)
57107 * Returns the id of the column at the specified index.
57108 * @param {Number} index The column index
57109 * @return {String} the id
57111 getColumnId : function(index){
57112 return this.config[index].id;
57116 * Returns the column for a specified id.
57117 * @param {String} id The column id
57118 * @return {Object} the column
57120 getColumnById : function(id){
57121 return this.lookup[id];
57126 * Returns the column for a specified dataIndex.
57127 * @param {String} dataIndex The column dataIndex
57128 * @return {Object|Boolean} the column or false if not found
57130 getColumnByDataIndex: function(dataIndex){
57131 var index = this.findColumnIndex(dataIndex);
57132 return index > -1 ? this.config[index] : false;
57136 * Returns the index for a specified column id.
57137 * @param {String} id The column id
57138 * @return {Number} the index, or -1 if not found
57140 getIndexById : function(id){
57141 for(var i = 0, len = this.config.length; i < len; i++){
57142 if(this.config[i].id == id){
57150 * Returns the index for a specified column dataIndex.
57151 * @param {String} dataIndex The column dataIndex
57152 * @return {Number} the index, or -1 if not found
57155 findColumnIndex : function(dataIndex){
57156 for(var i = 0, len = this.config.length; i < len; i++){
57157 if(this.config[i].dataIndex == dataIndex){
57165 moveColumn : function(oldIndex, newIndex){
57166 var c = this.config[oldIndex];
57167 this.config.splice(oldIndex, 1);
57168 this.config.splice(newIndex, 0, c);
57169 this.dataMap = null;
57170 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57173 isLocked : function(colIndex){
57174 return this.config[colIndex].locked === true;
57177 setLocked : function(colIndex, value, suppressEvent){
57178 if(this.isLocked(colIndex) == value){
57181 this.config[colIndex].locked = value;
57182 if(!suppressEvent){
57183 this.fireEvent("columnlockchange", this, colIndex, value);
57187 getTotalLockedWidth : function(){
57188 var totalWidth = 0;
57189 for(var i = 0; i < this.config.length; i++){
57190 if(this.isLocked(i) && !this.isHidden(i)){
57191 this.totalWidth += this.getColumnWidth(i);
57197 getLockedCount : function(){
57198 for(var i = 0, len = this.config.length; i < len; i++){
57199 if(!this.isLocked(i)){
57204 return this.config.length;
57208 * Returns the number of columns.
57211 getColumnCount : function(visibleOnly){
57212 if(visibleOnly === true){
57214 for(var i = 0, len = this.config.length; i < len; i++){
57215 if(!this.isHidden(i)){
57221 return this.config.length;
57225 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57226 * @param {Function} fn
57227 * @param {Object} scope (optional)
57228 * @return {Array} result
57230 getColumnsBy : function(fn, scope){
57232 for(var i = 0, len = this.config.length; i < len; i++){
57233 var c = this.config[i];
57234 if(fn.call(scope||this, c, i) === true){
57242 * Returns true if the specified column is sortable.
57243 * @param {Number} col The column index
57244 * @return {Boolean}
57246 isSortable : function(col){
57247 if(typeof this.config[col].sortable == "undefined"){
57248 return this.defaultSortable;
57250 return this.config[col].sortable;
57254 * Returns the rendering (formatting) function defined for the column.
57255 * @param {Number} col The column index.
57256 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57258 getRenderer : function(col){
57259 if(!this.config[col].renderer){
57260 return Roo.grid.ColumnModel.defaultRenderer;
57262 return this.config[col].renderer;
57266 * Sets the rendering (formatting) function for a column.
57267 * @param {Number} col The column index
57268 * @param {Function} fn The function to use to process the cell's raw data
57269 * to return HTML markup for the grid view. The render function is called with
57270 * the following parameters:<ul>
57271 * <li>Data value.</li>
57272 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57273 * <li>css A CSS style string to apply to the table cell.</li>
57274 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57275 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57276 * <li>Row index</li>
57277 * <li>Column index</li>
57278 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57280 setRenderer : function(col, fn){
57281 this.config[col].renderer = fn;
57285 * Returns the width for the specified column.
57286 * @param {Number} col The column index
57289 getColumnWidth : function(col){
57290 return this.config[col].width * 1 || this.defaultWidth;
57294 * Sets the width for a column.
57295 * @param {Number} col The column index
57296 * @param {Number} width The new width
57298 setColumnWidth : function(col, width, suppressEvent){
57299 this.config[col].width = width;
57300 this.totalWidth = null;
57301 if(!suppressEvent){
57302 this.fireEvent("widthchange", this, col, width);
57307 * Returns the total width of all columns.
57308 * @param {Boolean} includeHidden True to include hidden column widths
57311 getTotalWidth : function(includeHidden){
57312 if(!this.totalWidth){
57313 this.totalWidth = 0;
57314 for(var i = 0, len = this.config.length; i < len; i++){
57315 if(includeHidden || !this.isHidden(i)){
57316 this.totalWidth += this.getColumnWidth(i);
57320 return this.totalWidth;
57324 * Returns the header for the specified column.
57325 * @param {Number} col The column index
57328 getColumnHeader : function(col){
57329 return this.config[col].header;
57333 * Sets the header for a column.
57334 * @param {Number} col The column index
57335 * @param {String} header The new header
57337 setColumnHeader : function(col, header){
57338 this.config[col].header = header;
57339 this.fireEvent("headerchange", this, col, header);
57343 * Returns the tooltip for the specified column.
57344 * @param {Number} col The column index
57347 getColumnTooltip : function(col){
57348 return this.config[col].tooltip;
57351 * Sets the tooltip for a column.
57352 * @param {Number} col The column index
57353 * @param {String} tooltip The new tooltip
57355 setColumnTooltip : function(col, tooltip){
57356 this.config[col].tooltip = tooltip;
57360 * Returns the dataIndex for the specified column.
57361 * @param {Number} col The column index
57364 getDataIndex : function(col){
57365 return this.config[col].dataIndex;
57369 * Sets the dataIndex for a column.
57370 * @param {Number} col The column index
57371 * @param {Number} dataIndex The new dataIndex
57373 setDataIndex : function(col, dataIndex){
57374 this.config[col].dataIndex = dataIndex;
57380 * Returns true if the cell is editable.
57381 * @param {Number} colIndex The column index
57382 * @param {Number} rowIndex The row index - this is nto actually used..?
57383 * @return {Boolean}
57385 isCellEditable : function(colIndex, rowIndex){
57386 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57390 * Returns the editor defined for the cell/column.
57391 * return false or null to disable editing.
57392 * @param {Number} colIndex The column index
57393 * @param {Number} rowIndex The row index
57396 getCellEditor : function(colIndex, rowIndex){
57397 return this.config[colIndex].editor;
57401 * Sets if a column is editable.
57402 * @param {Number} col The column index
57403 * @param {Boolean} editable True if the column is editable
57405 setEditable : function(col, editable){
57406 this.config[col].editable = editable;
57411 * Returns true if the column is hidden.
57412 * @param {Number} colIndex The column index
57413 * @return {Boolean}
57415 isHidden : function(colIndex){
57416 return this.config[colIndex].hidden;
57421 * Returns true if the column width cannot be changed
57423 isFixed : function(colIndex){
57424 return this.config[colIndex].fixed;
57428 * Returns true if the column can be resized
57429 * @return {Boolean}
57431 isResizable : function(colIndex){
57432 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57435 * Sets if a column is hidden.
57436 * @param {Number} colIndex The column index
57437 * @param {Boolean} hidden True if the column is hidden
57439 setHidden : function(colIndex, hidden){
57440 this.config[colIndex].hidden = hidden;
57441 this.totalWidth = null;
57442 this.fireEvent("hiddenchange", this, colIndex, hidden);
57446 * Sets the editor for a column.
57447 * @param {Number} col The column index
57448 * @param {Object} editor The editor object
57450 setEditor : function(col, editor){
57451 this.config[col].editor = editor;
57455 Roo.grid.ColumnModel.defaultRenderer = function(value)
57457 if(typeof value == "object") {
57460 if(typeof value == "string" && value.length < 1){
57464 return String.format("{0}", value);
57467 // Alias for backwards compatibility
57468 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57471 * Ext JS Library 1.1.1
57472 * Copyright(c) 2006-2007, Ext JS, LLC.
57474 * Originally Released Under LGPL - original licence link has changed is not relivant.
57477 * <script type="text/javascript">
57481 * @class Roo.grid.AbstractSelectionModel
57482 * @extends Roo.util.Observable
57483 * Abstract base class for grid SelectionModels. It provides the interface that should be
57484 * implemented by descendant classes. This class should not be directly instantiated.
57487 Roo.grid.AbstractSelectionModel = function(){
57488 this.locked = false;
57489 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57492 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57493 /** @ignore Called by the grid automatically. Do not call directly. */
57494 init : function(grid){
57500 * Locks the selections.
57503 this.locked = true;
57507 * Unlocks the selections.
57509 unlock : function(){
57510 this.locked = false;
57514 * Returns true if the selections are locked.
57515 * @return {Boolean}
57517 isLocked : function(){
57518 return this.locked;
57522 * Ext JS Library 1.1.1
57523 * Copyright(c) 2006-2007, Ext JS, LLC.
57525 * Originally Released Under LGPL - original licence link has changed is not relivant.
57528 * <script type="text/javascript">
57531 * @extends Roo.grid.AbstractSelectionModel
57532 * @class Roo.grid.RowSelectionModel
57533 * The default SelectionModel used by {@link Roo.grid.Grid}.
57534 * It supports multiple selections and keyboard selection/navigation.
57536 * @param {Object} config
57538 Roo.grid.RowSelectionModel = function(config){
57539 Roo.apply(this, config);
57540 this.selections = new Roo.util.MixedCollection(false, function(o){
57545 this.lastActive = false;
57549 * @event selectionchange
57550 * Fires when the selection changes
57551 * @param {SelectionModel} this
57553 "selectionchange" : true,
57555 * @event afterselectionchange
57556 * Fires after the selection changes (eg. by key press or clicking)
57557 * @param {SelectionModel} this
57559 "afterselectionchange" : true,
57561 * @event beforerowselect
57562 * Fires when a row is selected being selected, return false to cancel.
57563 * @param {SelectionModel} this
57564 * @param {Number} rowIndex The selected index
57565 * @param {Boolean} keepExisting False if other selections will be cleared
57567 "beforerowselect" : true,
57570 * Fires when a row is selected.
57571 * @param {SelectionModel} this
57572 * @param {Number} rowIndex The selected index
57573 * @param {Roo.data.Record} r The record
57575 "rowselect" : true,
57577 * @event rowdeselect
57578 * Fires when a row is deselected.
57579 * @param {SelectionModel} this
57580 * @param {Number} rowIndex The selected index
57582 "rowdeselect" : true
57584 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57585 this.locked = false;
57588 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57590 * @cfg {Boolean} singleSelect
57591 * True to allow selection of only one row at a time (defaults to false)
57593 singleSelect : false,
57596 initEvents : function(){
57598 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57599 this.grid.on("mousedown", this.handleMouseDown, this);
57600 }else{ // allow click to work like normal
57601 this.grid.on("rowclick", this.handleDragableRowClick, this);
57604 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57605 "up" : function(e){
57607 this.selectPrevious(e.shiftKey);
57608 }else if(this.last !== false && this.lastActive !== false){
57609 var last = this.last;
57610 this.selectRange(this.last, this.lastActive-1);
57611 this.grid.getView().focusRow(this.lastActive);
57612 if(last !== false){
57616 this.selectFirstRow();
57618 this.fireEvent("afterselectionchange", this);
57620 "down" : function(e){
57622 this.selectNext(e.shiftKey);
57623 }else if(this.last !== false && this.lastActive !== false){
57624 var last = this.last;
57625 this.selectRange(this.last, this.lastActive+1);
57626 this.grid.getView().focusRow(this.lastActive);
57627 if(last !== false){
57631 this.selectFirstRow();
57633 this.fireEvent("afterselectionchange", this);
57638 var view = this.grid.view;
57639 view.on("refresh", this.onRefresh, this);
57640 view.on("rowupdated", this.onRowUpdated, this);
57641 view.on("rowremoved", this.onRemove, this);
57645 onRefresh : function(){
57646 var ds = this.grid.dataSource, i, v = this.grid.view;
57647 var s = this.selections;
57648 s.each(function(r){
57649 if((i = ds.indexOfId(r.id)) != -1){
57651 s.add(ds.getAt(i)); // updating the selection relate data
57659 onRemove : function(v, index, r){
57660 this.selections.remove(r);
57664 onRowUpdated : function(v, index, r){
57665 if(this.isSelected(r)){
57666 v.onRowSelect(index);
57672 * @param {Array} records The records to select
57673 * @param {Boolean} keepExisting (optional) True to keep existing selections
57675 selectRecords : function(records, keepExisting){
57677 this.clearSelections();
57679 var ds = this.grid.dataSource;
57680 for(var i = 0, len = records.length; i < len; i++){
57681 this.selectRow(ds.indexOf(records[i]), true);
57686 * Gets the number of selected rows.
57689 getCount : function(){
57690 return this.selections.length;
57694 * Selects the first row in the grid.
57696 selectFirstRow : function(){
57701 * Select the last row.
57702 * @param {Boolean} keepExisting (optional) True to keep existing selections
57704 selectLastRow : function(keepExisting){
57705 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57709 * Selects the row immediately following the last selected row.
57710 * @param {Boolean} keepExisting (optional) True to keep existing selections
57712 selectNext : function(keepExisting){
57713 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57714 this.selectRow(this.last+1, keepExisting);
57715 this.grid.getView().focusRow(this.last);
57720 * Selects the row that precedes the last selected row.
57721 * @param {Boolean} keepExisting (optional) True to keep existing selections
57723 selectPrevious : function(keepExisting){
57725 this.selectRow(this.last-1, keepExisting);
57726 this.grid.getView().focusRow(this.last);
57731 * Returns the selected records
57732 * @return {Array} Array of selected records
57734 getSelections : function(){
57735 return [].concat(this.selections.items);
57739 * Returns the first selected record.
57742 getSelected : function(){
57743 return this.selections.itemAt(0);
57748 * Clears all selections.
57750 clearSelections : function(fast){
57755 var ds = this.grid.dataSource;
57756 var s = this.selections;
57757 s.each(function(r){
57758 this.deselectRow(ds.indexOfId(r.id));
57762 this.selections.clear();
57769 * Selects all rows.
57771 selectAll : function(){
57775 this.selections.clear();
57776 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57777 this.selectRow(i, true);
57782 * Returns True if there is a selection.
57783 * @return {Boolean}
57785 hasSelection : function(){
57786 return this.selections.length > 0;
57790 * Returns True if the specified row is selected.
57791 * @param {Number/Record} record The record or index of the record to check
57792 * @return {Boolean}
57794 isSelected : function(index){
57795 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57796 return (r && this.selections.key(r.id) ? true : false);
57800 * Returns True if the specified record id is selected.
57801 * @param {String} id The id of record to check
57802 * @return {Boolean}
57804 isIdSelected : function(id){
57805 return (this.selections.key(id) ? true : false);
57809 handleMouseDown : function(e, t){
57810 var view = this.grid.getView(), rowIndex;
57811 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57814 if(e.shiftKey && this.last !== false){
57815 var last = this.last;
57816 this.selectRange(last, rowIndex, e.ctrlKey);
57817 this.last = last; // reset the last
57818 view.focusRow(rowIndex);
57820 var isSelected = this.isSelected(rowIndex);
57821 if(e.button !== 0 && isSelected){
57822 view.focusRow(rowIndex);
57823 }else if(e.ctrlKey && isSelected){
57824 this.deselectRow(rowIndex);
57825 }else if(!isSelected){
57826 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57827 view.focusRow(rowIndex);
57830 this.fireEvent("afterselectionchange", this);
57833 handleDragableRowClick : function(grid, rowIndex, e)
57835 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57836 this.selectRow(rowIndex, false);
57837 grid.view.focusRow(rowIndex);
57838 this.fireEvent("afterselectionchange", this);
57843 * Selects multiple rows.
57844 * @param {Array} rows Array of the indexes of the row to select
57845 * @param {Boolean} keepExisting (optional) True to keep existing selections
57847 selectRows : function(rows, keepExisting){
57849 this.clearSelections();
57851 for(var i = 0, len = rows.length; i < len; i++){
57852 this.selectRow(rows[i], true);
57857 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57858 * @param {Number} startRow The index of the first row in the range
57859 * @param {Number} endRow The index of the last row in the range
57860 * @param {Boolean} keepExisting (optional) True to retain existing selections
57862 selectRange : function(startRow, endRow, keepExisting){
57867 this.clearSelections();
57869 if(startRow <= endRow){
57870 for(var i = startRow; i <= endRow; i++){
57871 this.selectRow(i, true);
57874 for(var i = startRow; i >= endRow; i--){
57875 this.selectRow(i, true);
57881 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57882 * @param {Number} startRow The index of the first row in the range
57883 * @param {Number} endRow The index of the last row in the range
57885 deselectRange : function(startRow, endRow, preventViewNotify){
57889 for(var i = startRow; i <= endRow; i++){
57890 this.deselectRow(i, preventViewNotify);
57896 * @param {Number} row The index of the row to select
57897 * @param {Boolean} keepExisting (optional) True to keep existing selections
57899 selectRow : function(index, keepExisting, preventViewNotify){
57900 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57903 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57904 if(!keepExisting || this.singleSelect){
57905 this.clearSelections();
57907 var r = this.grid.dataSource.getAt(index);
57908 this.selections.add(r);
57909 this.last = this.lastActive = index;
57910 if(!preventViewNotify){
57911 this.grid.getView().onRowSelect(index);
57913 this.fireEvent("rowselect", this, index, r);
57914 this.fireEvent("selectionchange", this);
57920 * @param {Number} row The index of the row to deselect
57922 deselectRow : function(index, preventViewNotify){
57926 if(this.last == index){
57929 if(this.lastActive == index){
57930 this.lastActive = false;
57932 var r = this.grid.dataSource.getAt(index);
57933 this.selections.remove(r);
57934 if(!preventViewNotify){
57935 this.grid.getView().onRowDeselect(index);
57937 this.fireEvent("rowdeselect", this, index);
57938 this.fireEvent("selectionchange", this);
57942 restoreLast : function(){
57944 this.last = this._last;
57949 acceptsNav : function(row, col, cm){
57950 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57954 onEditorKey : function(field, e){
57955 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57960 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57962 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57964 }else if(k == e.ENTER && !e.ctrlKey){
57968 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57970 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57972 }else if(k == e.ESC){
57976 g.startEditing(newCell[0], newCell[1]);
57981 * Ext JS Library 1.1.1
57982 * Copyright(c) 2006-2007, Ext JS, LLC.
57984 * Originally Released Under LGPL - original licence link has changed is not relivant.
57987 * <script type="text/javascript">
57990 * @class Roo.grid.CellSelectionModel
57991 * @extends Roo.grid.AbstractSelectionModel
57992 * This class provides the basic implementation for cell selection in a grid.
57994 * @param {Object} config The object containing the configuration of this model.
57995 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
57997 Roo.grid.CellSelectionModel = function(config){
57998 Roo.apply(this, config);
58000 this.selection = null;
58004 * @event beforerowselect
58005 * Fires before a cell is selected.
58006 * @param {SelectionModel} this
58007 * @param {Number} rowIndex The selected row index
58008 * @param {Number} colIndex The selected cell index
58010 "beforecellselect" : true,
58012 * @event cellselect
58013 * Fires when a cell is selected.
58014 * @param {SelectionModel} this
58015 * @param {Number} rowIndex The selected row index
58016 * @param {Number} colIndex The selected cell index
58018 "cellselect" : true,
58020 * @event selectionchange
58021 * Fires when the active selection changes.
58022 * @param {SelectionModel} this
58023 * @param {Object} selection null for no selection or an object (o) with two properties
58025 <li>o.record: the record object for the row the selection is in</li>
58026 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58029 "selectionchange" : true,
58032 * Fires when the tab (or enter) was pressed on the last editable cell
58033 * You can use this to trigger add new row.
58034 * @param {SelectionModel} this
58038 * @event beforeeditnext
58039 * Fires before the next editable sell is made active
58040 * You can use this to skip to another cell or fire the tabend
58041 * if you set cell to false
58042 * @param {Object} eventdata object : { cell : [ row, col ] }
58044 "beforeeditnext" : true
58046 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58049 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58051 enter_is_tab: false,
58054 initEvents : function(){
58055 this.grid.on("mousedown", this.handleMouseDown, this);
58056 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58057 var view = this.grid.view;
58058 view.on("refresh", this.onViewChange, this);
58059 view.on("rowupdated", this.onRowUpdated, this);
58060 view.on("beforerowremoved", this.clearSelections, this);
58061 view.on("beforerowsinserted", this.clearSelections, this);
58062 if(this.grid.isEditor){
58063 this.grid.on("beforeedit", this.beforeEdit, this);
58068 beforeEdit : function(e){
58069 this.select(e.row, e.column, false, true, e.record);
58073 onRowUpdated : function(v, index, r){
58074 if(this.selection && this.selection.record == r){
58075 v.onCellSelect(index, this.selection.cell[1]);
58080 onViewChange : function(){
58081 this.clearSelections(true);
58085 * Returns the currently selected cell,.
58086 * @return {Array} The selected cell (row, column) or null if none selected.
58088 getSelectedCell : function(){
58089 return this.selection ? this.selection.cell : null;
58093 * Clears all selections.
58094 * @param {Boolean} true to prevent the gridview from being notified about the change.
58096 clearSelections : function(preventNotify){
58097 var s = this.selection;
58099 if(preventNotify !== true){
58100 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58102 this.selection = null;
58103 this.fireEvent("selectionchange", this, null);
58108 * Returns true if there is a selection.
58109 * @return {Boolean}
58111 hasSelection : function(){
58112 return this.selection ? true : false;
58116 handleMouseDown : function(e, t){
58117 var v = this.grid.getView();
58118 if(this.isLocked()){
58121 var row = v.findRowIndex(t);
58122 var cell = v.findCellIndex(t);
58123 if(row !== false && cell !== false){
58124 this.select(row, cell);
58130 * @param {Number} rowIndex
58131 * @param {Number} collIndex
58133 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58134 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58135 this.clearSelections();
58136 r = r || this.grid.dataSource.getAt(rowIndex);
58139 cell : [rowIndex, colIndex]
58141 if(!preventViewNotify){
58142 var v = this.grid.getView();
58143 v.onCellSelect(rowIndex, colIndex);
58144 if(preventFocus !== true){
58145 v.focusCell(rowIndex, colIndex);
58148 this.fireEvent("cellselect", this, rowIndex, colIndex);
58149 this.fireEvent("selectionchange", this, this.selection);
58154 isSelectable : function(rowIndex, colIndex, cm){
58155 return !cm.isHidden(colIndex);
58159 handleKeyDown : function(e){
58160 //Roo.log('Cell Sel Model handleKeyDown');
58161 if(!e.isNavKeyPress()){
58164 var g = this.grid, s = this.selection;
58167 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58169 this.select(cell[0], cell[1]);
58174 var walk = function(row, col, step){
58175 return g.walkCells(row, col, step, sm.isSelectable, sm);
58177 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58184 // handled by onEditorKey
58185 if (g.isEditor && g.editing) {
58189 newCell = walk(r, c-1, -1);
58191 newCell = walk(r, c+1, 1);
58196 newCell = walk(r+1, c, 1);
58200 newCell = walk(r-1, c, -1);
58204 newCell = walk(r, c+1, 1);
58208 newCell = walk(r, c-1, -1);
58213 if(g.isEditor && !g.editing){
58214 g.startEditing(r, c);
58223 this.select(newCell[0], newCell[1]);
58229 acceptsNav : function(row, col, cm){
58230 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58234 * @param {Number} field (not used) - as it's normally used as a listener
58235 * @param {Number} e - event - fake it by using
58237 * var e = Roo.EventObjectImpl.prototype;
58238 * e.keyCode = e.TAB
58242 onEditorKey : function(field, e){
58244 var k = e.getKey(),
58247 ed = g.activeEditor,
58249 ///Roo.log('onEditorKey' + k);
58252 if (this.enter_is_tab && k == e.ENTER) {
58258 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58260 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58266 } else if(k == e.ENTER && !e.ctrlKey){
58269 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58271 } else if(k == e.ESC){
58276 var ecall = { cell : newCell, forward : forward };
58277 this.fireEvent('beforeeditnext', ecall );
58278 newCell = ecall.cell;
58279 forward = ecall.forward;
58283 //Roo.log('next cell after edit');
58284 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58285 } else if (forward) {
58286 // tabbed past last
58287 this.fireEvent.defer(100, this, ['tabend',this]);
58292 * Ext JS Library 1.1.1
58293 * Copyright(c) 2006-2007, Ext JS, LLC.
58295 * Originally Released Under LGPL - original licence link has changed is not relivant.
58298 * <script type="text/javascript">
58302 * @class Roo.grid.EditorGrid
58303 * @extends Roo.grid.Grid
58304 * Class for creating and editable grid.
58305 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58306 * The container MUST have some type of size defined for the grid to fill. The container will be
58307 * automatically set to position relative if it isn't already.
58308 * @param {Object} dataSource The data model to bind to
58309 * @param {Object} colModel The column model with info about this grid's columns
58311 Roo.grid.EditorGrid = function(container, config){
58312 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58313 this.getGridEl().addClass("xedit-grid");
58315 if(!this.selModel){
58316 this.selModel = new Roo.grid.CellSelectionModel();
58319 this.activeEditor = null;
58323 * @event beforeedit
58324 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58325 * <ul style="padding:5px;padding-left:16px;">
58326 * <li>grid - This grid</li>
58327 * <li>record - The record being edited</li>
58328 * <li>field - The field name being edited</li>
58329 * <li>value - The value for the field being edited.</li>
58330 * <li>row - The grid row index</li>
58331 * <li>column - The grid column index</li>
58332 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58334 * @param {Object} e An edit event (see above for description)
58336 "beforeedit" : true,
58339 * Fires after a cell is edited. <br />
58340 * <ul style="padding:5px;padding-left:16px;">
58341 * <li>grid - This grid</li>
58342 * <li>record - The record being edited</li>
58343 * <li>field - The field name being edited</li>
58344 * <li>value - The value being set</li>
58345 * <li>originalValue - The original value for the field, before the edit.</li>
58346 * <li>row - The grid row index</li>
58347 * <li>column - The grid column index</li>
58349 * @param {Object} e An edit event (see above for description)
58351 "afteredit" : true,
58353 * @event validateedit
58354 * Fires after a cell is edited, but before the value is set in the record.
58355 * You can use this to modify the value being set in the field, Return false
58356 * to cancel the change. The edit event object has the following properties <br />
58357 * <ul style="padding:5px;padding-left:16px;">
58358 * <li>editor - This editor</li>
58359 * <li>grid - This grid</li>
58360 * <li>record - The record being edited</li>
58361 * <li>field - The field name being edited</li>
58362 * <li>value - The value being set</li>
58363 * <li>originalValue - The original value for the field, before the edit.</li>
58364 * <li>row - The grid row index</li>
58365 * <li>column - The grid column index</li>
58366 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58368 * @param {Object} e An edit event (see above for description)
58370 "validateedit" : true
58372 this.on("bodyscroll", this.stopEditing, this);
58373 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58376 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58378 * @cfg {Number} clicksToEdit
58379 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58386 trackMouseOver: false, // causes very odd FF errors
58388 onCellDblClick : function(g, row, col){
58389 this.startEditing(row, col);
58392 onEditComplete : function(ed, value, startValue){
58393 this.editing = false;
58394 this.activeEditor = null;
58395 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58397 var field = this.colModel.getDataIndex(ed.col);
58402 originalValue: startValue,
58409 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58412 if(String(value) !== String(startValue)){
58414 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58415 r.set(field, e.value);
58416 // if we are dealing with a combo box..
58417 // then we also set the 'name' colum to be the displayField
58418 if (ed.field.displayField && ed.field.name) {
58419 r.set(ed.field.name, ed.field.el.dom.value);
58422 delete e.cancel; //?? why!!!
58423 this.fireEvent("afteredit", e);
58426 this.fireEvent("afteredit", e); // always fire it!
58428 this.view.focusCell(ed.row, ed.col);
58432 * Starts editing the specified for the specified row/column
58433 * @param {Number} rowIndex
58434 * @param {Number} colIndex
58436 startEditing : function(row, col){
58437 this.stopEditing();
58438 if(this.colModel.isCellEditable(col, row)){
58439 this.view.ensureVisible(row, col, true);
58441 var r = this.dataSource.getAt(row);
58442 var field = this.colModel.getDataIndex(col);
58443 var cell = Roo.get(this.view.getCell(row,col));
58448 value: r.data[field],
58453 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58454 this.editing = true;
58455 var ed = this.colModel.getCellEditor(col, row);
58461 ed.render(ed.parentEl || document.body);
58467 (function(){ // complex but required for focus issues in safari, ie and opera
58471 ed.on("complete", this.onEditComplete, this, {single: true});
58472 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58473 this.activeEditor = ed;
58474 var v = r.data[field];
58475 ed.startEdit(this.view.getCell(row, col), v);
58476 // combo's with 'displayField and name set
58477 if (ed.field.displayField && ed.field.name) {
58478 ed.field.el.dom.value = r.data[ed.field.name];
58482 }).defer(50, this);
58488 * Stops any active editing
58490 stopEditing : function(){
58491 if(this.activeEditor){
58492 this.activeEditor.completeEdit();
58494 this.activeEditor = null;
58498 * Called to get grid's drag proxy text, by default returns this.ddText.
58501 getDragDropText : function(){
58502 var count = this.selModel.getSelectedCell() ? 1 : 0;
58503 return String.format(this.ddText, count, count == 1 ? '' : 's');
58508 * Ext JS Library 1.1.1
58509 * Copyright(c) 2006-2007, Ext JS, LLC.
58511 * Originally Released Under LGPL - original licence link has changed is not relivant.
58514 * <script type="text/javascript">
58517 // private - not really -- you end up using it !
58518 // This is a support class used internally by the Grid components
58521 * @class Roo.grid.GridEditor
58522 * @extends Roo.Editor
58523 * Class for creating and editable grid elements.
58524 * @param {Object} config any settings (must include field)
58526 Roo.grid.GridEditor = function(field, config){
58527 if (!config && field.field) {
58529 field = Roo.factory(config.field, Roo.form);
58531 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58532 field.monitorTab = false;
58535 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58538 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58541 alignment: "tl-tl",
58544 cls: "x-small-editor x-grid-editor",
58549 * Ext JS Library 1.1.1
58550 * Copyright(c) 2006-2007, Ext JS, LLC.
58552 * Originally Released Under LGPL - original licence link has changed is not relivant.
58555 * <script type="text/javascript">
58560 Roo.grid.PropertyRecord = Roo.data.Record.create([
58561 {name:'name',type:'string'}, 'value'
58565 Roo.grid.PropertyStore = function(grid, source){
58567 this.store = new Roo.data.Store({
58568 recordType : Roo.grid.PropertyRecord
58570 this.store.on('update', this.onUpdate, this);
58572 this.setSource(source);
58574 Roo.grid.PropertyStore.superclass.constructor.call(this);
58579 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58580 setSource : function(o){
58582 this.store.removeAll();
58585 if(this.isEditableValue(o[k])){
58586 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58589 this.store.loadRecords({records: data}, {}, true);
58592 onUpdate : function(ds, record, type){
58593 if(type == Roo.data.Record.EDIT){
58594 var v = record.data['value'];
58595 var oldValue = record.modified['value'];
58596 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58597 this.source[record.id] = v;
58599 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58606 getProperty : function(row){
58607 return this.store.getAt(row);
58610 isEditableValue: function(val){
58611 if(val && val instanceof Date){
58613 }else if(typeof val == 'object' || typeof val == 'function'){
58619 setValue : function(prop, value){
58620 this.source[prop] = value;
58621 this.store.getById(prop).set('value', value);
58624 getSource : function(){
58625 return this.source;
58629 Roo.grid.PropertyColumnModel = function(grid, store){
58632 g.PropertyColumnModel.superclass.constructor.call(this, [
58633 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58634 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58636 this.store = store;
58637 this.bselect = Roo.DomHelper.append(document.body, {
58638 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58639 {tag: 'option', value: 'true', html: 'true'},
58640 {tag: 'option', value: 'false', html: 'false'}
58643 Roo.id(this.bselect);
58646 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58647 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58648 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58649 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58650 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58652 this.renderCellDelegate = this.renderCell.createDelegate(this);
58653 this.renderPropDelegate = this.renderProp.createDelegate(this);
58656 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58660 valueText : 'Value',
58662 dateFormat : 'm/j/Y',
58665 renderDate : function(dateVal){
58666 return dateVal.dateFormat(this.dateFormat);
58669 renderBool : function(bVal){
58670 return bVal ? 'true' : 'false';
58673 isCellEditable : function(colIndex, rowIndex){
58674 return colIndex == 1;
58677 getRenderer : function(col){
58679 this.renderCellDelegate : this.renderPropDelegate;
58682 renderProp : function(v){
58683 return this.getPropertyName(v);
58686 renderCell : function(val){
58688 if(val instanceof Date){
58689 rv = this.renderDate(val);
58690 }else if(typeof val == 'boolean'){
58691 rv = this.renderBool(val);
58693 return Roo.util.Format.htmlEncode(rv);
58696 getPropertyName : function(name){
58697 var pn = this.grid.propertyNames;
58698 return pn && pn[name] ? pn[name] : name;
58701 getCellEditor : function(colIndex, rowIndex){
58702 var p = this.store.getProperty(rowIndex);
58703 var n = p.data['name'], val = p.data['value'];
58705 if(typeof(this.grid.customEditors[n]) == 'string'){
58706 return this.editors[this.grid.customEditors[n]];
58708 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58709 return this.grid.customEditors[n];
58711 if(val instanceof Date){
58712 return this.editors['date'];
58713 }else if(typeof val == 'number'){
58714 return this.editors['number'];
58715 }else if(typeof val == 'boolean'){
58716 return this.editors['boolean'];
58718 return this.editors['string'];
58724 * @class Roo.grid.PropertyGrid
58725 * @extends Roo.grid.EditorGrid
58726 * This class represents the interface of a component based property grid control.
58727 * <br><br>Usage:<pre><code>
58728 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58736 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58737 * The container MUST have some type of size defined for the grid to fill. The container will be
58738 * automatically set to position relative if it isn't already.
58739 * @param {Object} config A config object that sets properties on this grid.
58741 Roo.grid.PropertyGrid = function(container, config){
58742 config = config || {};
58743 var store = new Roo.grid.PropertyStore(this);
58744 this.store = store;
58745 var cm = new Roo.grid.PropertyColumnModel(this, store);
58746 store.store.sort('name', 'ASC');
58747 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58750 enableColLock:false,
58751 enableColumnMove:false,
58753 trackMouseOver: false,
58756 this.getGridEl().addClass('x-props-grid');
58757 this.lastEditRow = null;
58758 this.on('columnresize', this.onColumnResize, this);
58761 * @event beforepropertychange
58762 * Fires before a property changes (return false to stop?)
58763 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58764 * @param {String} id Record Id
58765 * @param {String} newval New Value
58766 * @param {String} oldval Old Value
58768 "beforepropertychange": true,
58770 * @event propertychange
58771 * Fires after a property changes
58772 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58773 * @param {String} id Record Id
58774 * @param {String} newval New Value
58775 * @param {String} oldval Old Value
58777 "propertychange": true
58779 this.customEditors = this.customEditors || {};
58781 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58784 * @cfg {Object} customEditors map of colnames=> custom editors.
58785 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58786 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58787 * false disables editing of the field.
58791 * @cfg {Object} propertyNames map of property Names to their displayed value
58794 render : function(){
58795 Roo.grid.PropertyGrid.superclass.render.call(this);
58796 this.autoSize.defer(100, this);
58799 autoSize : function(){
58800 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58802 this.view.fitColumns();
58806 onColumnResize : function(){
58807 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58811 * Sets the data for the Grid
58812 * accepts a Key => Value object of all the elements avaiable.
58813 * @param {Object} data to appear in grid.
58815 setSource : function(source){
58816 this.store.setSource(source);
58820 * Gets all the data from the grid.
58821 * @return {Object} data data stored in grid
58823 getSource : function(){
58824 return this.store.getSource();
58833 * @class Roo.grid.Calendar
58834 * @extends Roo.util.Grid
58835 * This class extends the Grid to provide a calendar widget
58836 * <br><br>Usage:<pre><code>
58837 var grid = new Roo.grid.Calendar("my-container-id", {
58840 selModel: mySelectionModel,
58841 autoSizeColumns: true,
58842 monitorWindowResize: false,
58843 trackMouseOver: true
58844 eventstore : real data store..
58850 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58851 * The container MUST have some type of size defined for the grid to fill. The container will be
58852 * automatically set to position relative if it isn't already.
58853 * @param {Object} config A config object that sets properties on this grid.
58855 Roo.grid.Calendar = function(container, config){
58856 // initialize the container
58857 this.container = Roo.get(container);
58858 this.container.update("");
58859 this.container.setStyle("overflow", "hidden");
58860 this.container.addClass('x-grid-container');
58862 this.id = this.container.id;
58864 Roo.apply(this, config);
58865 // check and correct shorthanded configs
58869 for (var r = 0;r < 6;r++) {
58872 for (var c =0;c < 7;c++) {
58876 if (this.eventStore) {
58877 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58878 this.eventStore.on('load',this.onLoad, this);
58879 this.eventStore.on('beforeload',this.clearEvents, this);
58883 this.dataSource = new Roo.data.Store({
58884 proxy: new Roo.data.MemoryProxy(rows),
58885 reader: new Roo.data.ArrayReader({}, [
58886 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58889 this.dataSource.load();
58890 this.ds = this.dataSource;
58891 this.ds.xmodule = this.xmodule || false;
58894 var cellRender = function(v,x,r)
58896 return String.format(
58897 '<div class="fc-day fc-widget-content"><div>' +
58898 '<div class="fc-event-container"></div>' +
58899 '<div class="fc-day-number">{0}</div>'+
58901 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58902 '</div></div>', v);
58907 this.colModel = new Roo.grid.ColumnModel( [
58909 xtype: 'ColumnModel',
58911 dataIndex : 'weekday0',
58913 renderer : cellRender
58916 xtype: 'ColumnModel',
58918 dataIndex : 'weekday1',
58920 renderer : cellRender
58923 xtype: 'ColumnModel',
58925 dataIndex : 'weekday2',
58926 header : 'Tuesday',
58927 renderer : cellRender
58930 xtype: 'ColumnModel',
58932 dataIndex : 'weekday3',
58933 header : 'Wednesday',
58934 renderer : cellRender
58937 xtype: 'ColumnModel',
58939 dataIndex : 'weekday4',
58940 header : 'Thursday',
58941 renderer : cellRender
58944 xtype: 'ColumnModel',
58946 dataIndex : 'weekday5',
58948 renderer : cellRender
58951 xtype: 'ColumnModel',
58953 dataIndex : 'weekday6',
58954 header : 'Saturday',
58955 renderer : cellRender
58958 this.cm = this.colModel;
58959 this.cm.xmodule = this.xmodule || false;
58963 //this.selModel = new Roo.grid.CellSelectionModel();
58964 //this.sm = this.selModel;
58965 //this.selModel.init(this);
58969 this.container.setWidth(this.width);
58973 this.container.setHeight(this.height);
58980 * The raw click event for the entire grid.
58981 * @param {Roo.EventObject} e
58986 * The raw dblclick event for the entire grid.
58987 * @param {Roo.EventObject} e
58991 * @event contextmenu
58992 * The raw contextmenu event for the entire grid.
58993 * @param {Roo.EventObject} e
58995 "contextmenu" : true,
58998 * The raw mousedown event for the entire grid.
58999 * @param {Roo.EventObject} e
59001 "mousedown" : true,
59004 * The raw mouseup event for the entire grid.
59005 * @param {Roo.EventObject} e
59010 * The raw mouseover event for the entire grid.
59011 * @param {Roo.EventObject} e
59013 "mouseover" : true,
59016 * The raw mouseout event for the entire grid.
59017 * @param {Roo.EventObject} e
59022 * The raw keypress event for the entire grid.
59023 * @param {Roo.EventObject} e
59028 * The raw keydown event for the entire grid.
59029 * @param {Roo.EventObject} e
59037 * Fires when a cell is clicked
59038 * @param {Grid} this
59039 * @param {Number} rowIndex
59040 * @param {Number} columnIndex
59041 * @param {Roo.EventObject} e
59043 "cellclick" : true,
59045 * @event celldblclick
59046 * Fires when a cell is double clicked
59047 * @param {Grid} this
59048 * @param {Number} rowIndex
59049 * @param {Number} columnIndex
59050 * @param {Roo.EventObject} e
59052 "celldblclick" : true,
59055 * Fires when a row is clicked
59056 * @param {Grid} this
59057 * @param {Number} rowIndex
59058 * @param {Roo.EventObject} e
59062 * @event rowdblclick
59063 * Fires when a row is double clicked
59064 * @param {Grid} this
59065 * @param {Number} rowIndex
59066 * @param {Roo.EventObject} e
59068 "rowdblclick" : true,
59070 * @event headerclick
59071 * Fires when a header is clicked
59072 * @param {Grid} this
59073 * @param {Number} columnIndex
59074 * @param {Roo.EventObject} e
59076 "headerclick" : true,
59078 * @event headerdblclick
59079 * Fires when a header cell is double clicked
59080 * @param {Grid} this
59081 * @param {Number} columnIndex
59082 * @param {Roo.EventObject} e
59084 "headerdblclick" : true,
59086 * @event rowcontextmenu
59087 * Fires when a row is right clicked
59088 * @param {Grid} this
59089 * @param {Number} rowIndex
59090 * @param {Roo.EventObject} e
59092 "rowcontextmenu" : true,
59094 * @event cellcontextmenu
59095 * Fires when a cell is right clicked
59096 * @param {Grid} this
59097 * @param {Number} rowIndex
59098 * @param {Number} cellIndex
59099 * @param {Roo.EventObject} e
59101 "cellcontextmenu" : true,
59103 * @event headercontextmenu
59104 * Fires when a header is right clicked
59105 * @param {Grid} this
59106 * @param {Number} columnIndex
59107 * @param {Roo.EventObject} e
59109 "headercontextmenu" : true,
59111 * @event bodyscroll
59112 * Fires when the body element is scrolled
59113 * @param {Number} scrollLeft
59114 * @param {Number} scrollTop
59116 "bodyscroll" : true,
59118 * @event columnresize
59119 * Fires when the user resizes a column
59120 * @param {Number} columnIndex
59121 * @param {Number} newSize
59123 "columnresize" : true,
59125 * @event columnmove
59126 * Fires when the user moves a column
59127 * @param {Number} oldIndex
59128 * @param {Number} newIndex
59130 "columnmove" : true,
59133 * Fires when row(s) start being dragged
59134 * @param {Grid} this
59135 * @param {Roo.GridDD} dd The drag drop object
59136 * @param {event} e The raw browser event
59138 "startdrag" : true,
59141 * Fires when a drag operation is complete
59142 * @param {Grid} this
59143 * @param {Roo.GridDD} dd The drag drop object
59144 * @param {event} e The raw browser event
59149 * Fires when dragged row(s) are dropped on a valid DD target
59150 * @param {Grid} this
59151 * @param {Roo.GridDD} dd The drag drop object
59152 * @param {String} targetId The target drag drop object
59153 * @param {event} e The raw browser event
59158 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59159 * @param {Grid} this
59160 * @param {Roo.GridDD} dd The drag drop object
59161 * @param {String} targetId The target drag drop object
59162 * @param {event} e The raw browser event
59167 * Fires when the dragged row(s) first cross another DD target while being dragged
59168 * @param {Grid} this
59169 * @param {Roo.GridDD} dd The drag drop object
59170 * @param {String} targetId The target drag drop object
59171 * @param {event} e The raw browser event
59173 "dragenter" : true,
59176 * Fires when the dragged row(s) leave another DD target while being dragged
59177 * @param {Grid} this
59178 * @param {Roo.GridDD} dd The drag drop object
59179 * @param {String} targetId The target drag drop object
59180 * @param {event} e The raw browser event
59185 * Fires when a row is rendered, so you can change add a style to it.
59186 * @param {GridView} gridview The grid view
59187 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59193 * Fires when the grid is rendered
59194 * @param {Grid} grid
59199 * Fires when a date is selected
59200 * @param {DatePicker} this
59201 * @param {Date} date The selected date
59205 * @event monthchange
59206 * Fires when the displayed month changes
59207 * @param {DatePicker} this
59208 * @param {Date} date The selected month
59210 'monthchange': true,
59212 * @event evententer
59213 * Fires when mouse over an event
59214 * @param {Calendar} this
59215 * @param {event} Event
59217 'evententer': true,
59219 * @event eventleave
59220 * Fires when the mouse leaves an
59221 * @param {Calendar} this
59224 'eventleave': true,
59226 * @event eventclick
59227 * Fires when the mouse click an
59228 * @param {Calendar} this
59231 'eventclick': true,
59233 * @event eventrender
59234 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59235 * @param {Calendar} this
59236 * @param {data} data to be modified
59238 'eventrender': true
59242 Roo.grid.Grid.superclass.constructor.call(this);
59243 this.on('render', function() {
59244 this.view.el.addClass('x-grid-cal');
59246 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59250 if (!Roo.grid.Calendar.style) {
59251 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59254 '.x-grid-cal .x-grid-col' : {
59255 height: 'auto !important',
59256 'vertical-align': 'top'
59258 '.x-grid-cal .fc-event-hori' : {
59269 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59271 * @cfg {Store} eventStore The store that loads events.
59276 activeDate : false,
59279 monitorWindowResize : false,
59282 resizeColumns : function() {
59283 var col = (this.view.el.getWidth() / 7) - 3;
59284 // loop through cols, and setWidth
59285 for(var i =0 ; i < 7 ; i++){
59286 this.cm.setColumnWidth(i, col);
59289 setDate :function(date) {
59291 Roo.log('setDate?');
59293 this.resizeColumns();
59294 var vd = this.activeDate;
59295 this.activeDate = date;
59296 // if(vd && this.el){
59297 // var t = date.getTime();
59298 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59299 // Roo.log('using add remove');
59301 // this.fireEvent('monthchange', this, date);
59303 // this.cells.removeClass("fc-state-highlight");
59304 // this.cells.each(function(c){
59305 // if(c.dateValue == t){
59306 // c.addClass("fc-state-highlight");
59307 // setTimeout(function(){
59308 // try{c.dom.firstChild.focus();}catch(e){}
59318 var days = date.getDaysInMonth();
59320 var firstOfMonth = date.getFirstDateOfMonth();
59321 var startingPos = firstOfMonth.getDay()-this.startDay;
59323 if(startingPos < this.startDay){
59327 var pm = date.add(Date.MONTH, -1);
59328 var prevStart = pm.getDaysInMonth()-startingPos;
59332 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59334 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59335 //this.cells.addClassOnOver('fc-state-hover');
59337 var cells = this.cells.elements;
59338 var textEls = this.textNodes;
59340 //Roo.each(cells, function(cell){
59341 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59344 days += startingPos;
59346 // convert everything to numbers so it's fast
59347 var day = 86400000;
59348 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59351 //Roo.log(prevStart);
59353 var today = new Date().clearTime().getTime();
59354 var sel = date.clearTime().getTime();
59355 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59356 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59357 var ddMatch = this.disabledDatesRE;
59358 var ddText = this.disabledDatesText;
59359 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59360 var ddaysText = this.disabledDaysText;
59361 var format = this.format;
59363 var setCellClass = function(cal, cell){
59365 //Roo.log('set Cell Class');
59367 var t = d.getTime();
59372 cell.dateValue = t;
59374 cell.className += " fc-today";
59375 cell.className += " fc-state-highlight";
59376 cell.title = cal.todayText;
59379 // disable highlight in other month..
59380 cell.className += " fc-state-highlight";
59385 //cell.className = " fc-state-disabled";
59386 cell.title = cal.minText;
59390 //cell.className = " fc-state-disabled";
59391 cell.title = cal.maxText;
59395 if(ddays.indexOf(d.getDay()) != -1){
59396 // cell.title = ddaysText;
59397 // cell.className = " fc-state-disabled";
59400 if(ddMatch && format){
59401 var fvalue = d.dateFormat(format);
59402 if(ddMatch.test(fvalue)){
59403 cell.title = ddText.replace("%0", fvalue);
59404 cell.className = " fc-state-disabled";
59408 if (!cell.initialClassName) {
59409 cell.initialClassName = cell.dom.className;
59412 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59417 for(; i < startingPos; i++) {
59418 cells[i].dayName = (++prevStart);
59419 Roo.log(textEls[i]);
59420 d.setDate(d.getDate()+1);
59422 //cells[i].className = "fc-past fc-other-month";
59423 setCellClass(this, cells[i]);
59428 for(; i < days; i++){
59429 intDay = i - startingPos + 1;
59430 cells[i].dayName = (intDay);
59431 d.setDate(d.getDate()+1);
59433 cells[i].className = ''; // "x-date-active";
59434 setCellClass(this, cells[i]);
59438 for(; i < 42; i++) {
59439 //textEls[i].innerHTML = (++extraDays);
59441 d.setDate(d.getDate()+1);
59442 cells[i].dayName = (++extraDays);
59443 cells[i].className = "fc-future fc-other-month";
59444 setCellClass(this, cells[i]);
59447 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59449 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59451 // this will cause all the cells to mis
59454 for (var r = 0;r < 6;r++) {
59455 for (var c =0;c < 7;c++) {
59456 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59460 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59461 for(i=0;i<cells.length;i++) {
59463 this.cells.elements[i].dayName = cells[i].dayName ;
59464 this.cells.elements[i].className = cells[i].className;
59465 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59466 this.cells.elements[i].title = cells[i].title ;
59467 this.cells.elements[i].dateValue = cells[i].dateValue ;
59473 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59474 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59476 ////if(totalRows != 6){
59477 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59478 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59481 this.fireEvent('monthchange', this, date);
59486 * Returns the grid's SelectionModel.
59487 * @return {SelectionModel}
59489 getSelectionModel : function(){
59490 if(!this.selModel){
59491 this.selModel = new Roo.grid.CellSelectionModel();
59493 return this.selModel;
59497 this.eventStore.load()
59503 findCell : function(dt) {
59504 dt = dt.clearTime().getTime();
59506 this.cells.each(function(c){
59507 //Roo.log("check " +c.dateValue + '?=' + dt);
59508 if(c.dateValue == dt){
59518 findCells : function(rec) {
59519 var s = rec.data.start_dt.clone().clearTime().getTime();
59521 var e= rec.data.end_dt.clone().clearTime().getTime();
59524 this.cells.each(function(c){
59525 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59527 if(c.dateValue > e){
59530 if(c.dateValue < s){
59539 findBestRow: function(cells)
59543 for (var i =0 ; i < cells.length;i++) {
59544 ret = Math.max(cells[i].rows || 0,ret);
59551 addItem : function(rec)
59553 // look for vertical location slot in
59554 var cells = this.findCells(rec);
59556 rec.row = this.findBestRow(cells);
59558 // work out the location.
59562 for(var i =0; i < cells.length; i++) {
59570 if (crow.start.getY() == cells[i].getY()) {
59572 crow.end = cells[i];
59588 for (var i = 0; i < cells.length;i++) {
59589 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59596 clearEvents: function() {
59598 if (!this.eventStore.getCount()) {
59601 // reset number of rows in cells.
59602 Roo.each(this.cells.elements, function(c){
59606 this.eventStore.each(function(e) {
59607 this.clearEvent(e);
59612 clearEvent : function(ev)
59615 Roo.each(ev.els, function(el) {
59616 el.un('mouseenter' ,this.onEventEnter, this);
59617 el.un('mouseleave' ,this.onEventLeave, this);
59625 renderEvent : function(ev,ctr) {
59627 ctr = this.view.el.select('.fc-event-container',true).first();
59631 this.clearEvent(ev);
59637 var cells = ev.cells;
59638 var rows = ev.rows;
59639 this.fireEvent('eventrender', this, ev);
59641 for(var i =0; i < rows.length; i++) {
59645 cls += ' fc-event-start';
59647 if ((i+1) == rows.length) {
59648 cls += ' fc-event-end';
59651 //Roo.log(ev.data);
59652 // how many rows should it span..
59653 var cg = this.eventTmpl.append(ctr,Roo.apply({
59656 }, ev.data) , true);
59659 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59660 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59661 cg.on('click', this.onEventClick, this, ev);
59665 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59666 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59669 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59670 cg.setWidth(ebox.right - sbox.x -2);
59674 renderEvents: function()
59676 // first make sure there is enough space..
59678 if (!this.eventTmpl) {
59679 this.eventTmpl = new Roo.Template(
59680 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59681 '<div class="fc-event-inner">' +
59682 '<span class="fc-event-time">{time}</span>' +
59683 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59685 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59693 this.cells.each(function(c) {
59694 //Roo.log(c.select('.fc-day-content div',true).first());
59695 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59698 var ctr = this.view.el.select('.fc-event-container',true).first();
59701 this.eventStore.each(function(ev){
59703 this.renderEvent(ev);
59707 this.view.layout();
59711 onEventEnter: function (e, el,event,d) {
59712 this.fireEvent('evententer', this, el, event);
59715 onEventLeave: function (e, el,event,d) {
59716 this.fireEvent('eventleave', this, el, event);
59719 onEventClick: function (e, el,event,d) {
59720 this.fireEvent('eventclick', this, el, event);
59723 onMonthChange: function () {
59727 onLoad: function () {
59729 //Roo.log('calendar onload');
59731 if(this.eventStore.getCount() > 0){
59735 this.eventStore.each(function(d){
59740 if (typeof(add.end_dt) == 'undefined') {
59741 Roo.log("Missing End time in calendar data: ");
59745 if (typeof(add.start_dt) == 'undefined') {
59746 Roo.log("Missing Start time in calendar data: ");
59750 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59751 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59752 add.id = add.id || d.id;
59753 add.title = add.title || '??';
59761 this.renderEvents();
59771 render : function ()
59775 if (!this.view.el.hasClass('course-timesheet')) {
59776 this.view.el.addClass('course-timesheet');
59778 if (this.tsStyle) {
59783 Roo.log(_this.grid.view.el.getWidth());
59786 this.tsStyle = Roo.util.CSS.createStyleSheet({
59787 '.course-timesheet .x-grid-row' : {
59790 '.x-grid-row td' : {
59791 'vertical-align' : 0
59793 '.course-edit-link' : {
59795 'text-overflow' : 'ellipsis',
59796 'overflow' : 'hidden',
59797 'white-space' : 'nowrap',
59798 'cursor' : 'pointer'
59803 '.de-act-sup-link' : {
59804 'color' : 'purple',
59805 'text-decoration' : 'line-through'
59809 'text-decoration' : 'line-through'
59811 '.course-timesheet .course-highlight' : {
59812 'border-top-style': 'dashed !important',
59813 'border-bottom-bottom': 'dashed !important'
59815 '.course-timesheet .course-item' : {
59816 'font-family' : 'tahoma, arial, helvetica',
59817 'font-size' : '11px',
59818 'overflow' : 'hidden',
59819 'padding-left' : '10px',
59820 'padding-right' : '10px',
59821 'padding-top' : '10px'
59829 monitorWindowResize : false,
59830 cellrenderer : function(v,x,r)
59835 xtype: 'CellSelectionModel',
59842 beforeload : function (_self, options)
59844 options.params = options.params || {};
59845 options.params._month = _this.monthField.getValue();
59846 options.params.limit = 9999;
59847 options.params['sort'] = 'when_dt';
59848 options.params['dir'] = 'ASC';
59849 this.proxy.loadResponse = this.loadResponse;
59851 //this.addColumns();
59853 load : function (_self, records, options)
59855 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59856 // if you click on the translation.. you can edit it...
59857 var el = Roo.get(this);
59858 var id = el.dom.getAttribute('data-id');
59859 var d = el.dom.getAttribute('data-date');
59860 var t = el.dom.getAttribute('data-time');
59861 //var id = this.child('span').dom.textContent;
59864 Pman.Dialog.CourseCalendar.show({
59868 productitem_active : id ? 1 : 0
59870 _this.grid.ds.load({});
59875 _this.panel.fireEvent('resize', [ '', '' ]);
59878 loadResponse : function(o, success, response){
59879 // this is overridden on before load..
59881 Roo.log("our code?");
59882 //Roo.log(success);
59883 //Roo.log(response)
59884 delete this.activeRequest;
59886 this.fireEvent("loadexception", this, o, response);
59887 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59892 result = o.reader.read(response);
59894 Roo.log("load exception?");
59895 this.fireEvent("loadexception", this, o, response, e);
59896 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59899 Roo.log("ready...");
59900 // loop through result.records;
59901 // and set this.tdate[date] = [] << array of records..
59903 Roo.each(result.records, function(r){
59905 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59906 _this.tdata[r.data.when_dt.format('j')] = [];
59908 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59911 //Roo.log(_this.tdata);
59913 result.records = [];
59914 result.totalRecords = 6;
59916 // let's generate some duumy records for the rows.
59917 //var st = _this.dateField.getValue();
59919 // work out monday..
59920 //st = st.add(Date.DAY, -1 * st.format('w'));
59922 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59924 var firstOfMonth = date.getFirstDayOfMonth();
59925 var days = date.getDaysInMonth();
59927 var firstAdded = false;
59928 for (var i = 0; i < result.totalRecords ; i++) {
59929 //var d= st.add(Date.DAY, i);
59932 for(var w = 0 ; w < 7 ; w++){
59933 if(!firstAdded && firstOfMonth != w){
59940 var dd = (d > 0 && d < 10) ? "0"+d : d;
59941 row['weekday'+w] = String.format(
59942 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59943 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59945 date.format('Y-m-')+dd
59948 if(typeof(_this.tdata[d]) != 'undefined'){
59949 Roo.each(_this.tdata[d], function(r){
59953 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59954 if(r.parent_id*1>0){
59955 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59958 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59959 deactive = 'de-act-link';
59962 row['weekday'+w] += String.format(
59963 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59965 r.product_id_name, //1
59966 r.when_dt.format('h:ia'), //2
59976 // only do this if something added..
59978 result.records.push(_this.grid.dataSource.reader.newRow(row));
59982 // push it twice. (second one with an hour..
59986 this.fireEvent("load", this, o, o.request.arg);
59987 o.request.callback.call(o.request.scope, result, o.request.arg, true);
59989 sortInfo : {field: 'when_dt', direction : 'ASC' },
59991 xtype: 'HttpProxy',
59994 url : baseURL + '/Roo/Shop_course.php'
59997 xtype: 'JsonReader',
60014 'name': 'parent_id',
60018 'name': 'product_id',
60022 'name': 'productitem_id',
60040 click : function (_self, e)
60042 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60043 sd.setMonth(sd.getMonth()-1);
60044 _this.monthField.setValue(sd.format('Y-m-d'));
60045 _this.grid.ds.load({});
60051 xtype: 'Separator',
60055 xtype: 'MonthField',
60058 render : function (_self)
60060 _this.monthField = _self;
60061 // _this.monthField.set today
60063 select : function (combo, date)
60065 _this.grid.ds.load({});
60068 value : (function() { return new Date(); })()
60071 xtype: 'Separator',
60077 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60087 click : function (_self, e)
60089 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60090 sd.setMonth(sd.getMonth()+1);
60091 _this.monthField.setValue(sd.format('Y-m-d'));
60092 _this.grid.ds.load({});
60105 * Ext JS Library 1.1.1
60106 * Copyright(c) 2006-2007, Ext JS, LLC.
60108 * Originally Released Under LGPL - original licence link has changed is not relivant.
60111 * <script type="text/javascript">
60115 * @class Roo.LoadMask
60116 * A simple utility class for generically masking elements while loading data. If the element being masked has
60117 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60118 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60119 * element's UpdateManager load indicator and will be destroyed after the initial load.
60121 * Create a new LoadMask
60122 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60123 * @param {Object} config The config object
60125 Roo.LoadMask = function(el, config){
60126 this.el = Roo.get(el);
60127 Roo.apply(this, config);
60129 this.store.on('beforeload', this.onBeforeLoad, this);
60130 this.store.on('load', this.onLoad, this);
60131 this.store.on('loadexception', this.onLoadException, this);
60132 this.removeMask = false;
60134 var um = this.el.getUpdateManager();
60135 um.showLoadIndicator = false; // disable the default indicator
60136 um.on('beforeupdate', this.onBeforeLoad, this);
60137 um.on('update', this.onLoad, this);
60138 um.on('failure', this.onLoad, this);
60139 this.removeMask = true;
60143 Roo.LoadMask.prototype = {
60145 * @cfg {Boolean} removeMask
60146 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60147 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60150 * @cfg {String} msg
60151 * The text to display in a centered loading message box (defaults to 'Loading...')
60153 msg : 'Loading...',
60155 * @cfg {String} msgCls
60156 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60158 msgCls : 'x-mask-loading',
60161 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60167 * Disables the mask to prevent it from being displayed
60169 disable : function(){
60170 this.disabled = true;
60174 * Enables the mask so that it can be displayed
60176 enable : function(){
60177 this.disabled = false;
60180 onLoadException : function()
60182 Roo.log(arguments);
60184 if (typeof(arguments[3]) != 'undefined') {
60185 Roo.MessageBox.alert("Error loading",arguments[3]);
60189 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60190 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60197 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60200 onLoad : function()
60202 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60206 onBeforeLoad : function(){
60207 if(!this.disabled){
60208 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60213 destroy : function(){
60215 this.store.un('beforeload', this.onBeforeLoad, this);
60216 this.store.un('load', this.onLoad, this);
60217 this.store.un('loadexception', this.onLoadException, this);
60219 var um = this.el.getUpdateManager();
60220 um.un('beforeupdate', this.onBeforeLoad, this);
60221 um.un('update', this.onLoad, this);
60222 um.un('failure', this.onLoad, this);
60227 * Ext JS Library 1.1.1
60228 * Copyright(c) 2006-2007, Ext JS, LLC.
60230 * Originally Released Under LGPL - original licence link has changed is not relivant.
60233 * <script type="text/javascript">
60238 * @class Roo.XTemplate
60239 * @extends Roo.Template
60240 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60242 var t = new Roo.XTemplate(
60243 '<select name="{name}">',
60244 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60248 // then append, applying the master template values
60251 * Supported features:
60256 {a_variable} - output encoded.
60257 {a_variable.format:("Y-m-d")} - call a method on the variable
60258 {a_variable:raw} - unencoded output
60259 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60260 {a_variable:this.method_on_template(...)} - call a method on the template object.
60265 <tpl for="a_variable or condition.."></tpl>
60266 <tpl if="a_variable or condition"></tpl>
60267 <tpl exec="some javascript"></tpl>
60268 <tpl name="named_template"></tpl> (experimental)
60270 <tpl for="."></tpl> - just iterate the property..
60271 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60275 Roo.XTemplate = function()
60277 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60284 Roo.extend(Roo.XTemplate, Roo.Template, {
60287 * The various sub templates
60292 * basic tag replacing syntax
60295 * // you can fake an object call by doing this
60299 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60302 * compile the template
60304 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60307 compile: function()
60311 s = ['<tpl>', s, '</tpl>'].join('');
60313 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60314 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60315 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60316 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60317 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60322 while(true == !!(m = s.match(re))){
60323 var forMatch = m[0].match(nameRe),
60324 ifMatch = m[0].match(ifRe),
60325 execMatch = m[0].match(execRe),
60326 namedMatch = m[0].match(namedRe),
60331 name = forMatch && forMatch[1] ? forMatch[1] : '';
60334 // if - puts fn into test..
60335 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60337 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60342 // exec - calls a function... returns empty if true is returned.
60343 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60345 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60353 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60354 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60355 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60358 var uid = namedMatch ? namedMatch[1] : id;
60362 id: namedMatch ? namedMatch[1] : id,
60369 s = s.replace(m[0], '');
60371 s = s.replace(m[0], '{xtpl'+ id + '}');
60376 for(var i = tpls.length-1; i >= 0; --i){
60377 this.compileTpl(tpls[i]);
60378 this.tpls[tpls[i].id] = tpls[i];
60380 this.master = tpls[tpls.length-1];
60384 * same as applyTemplate, except it's done to one of the subTemplates
60385 * when using named templates, you can do:
60387 * var str = pl.applySubTemplate('your-name', values);
60390 * @param {Number} id of the template
60391 * @param {Object} values to apply to template
60392 * @param {Object} parent (normaly the instance of this object)
60394 applySubTemplate : function(id, values, parent)
60398 var t = this.tpls[id];
60402 if(t.test && !t.test.call(this, values, parent)){
60406 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60407 Roo.log(e.toString());
60413 if(t.exec && t.exec.call(this, values, parent)){
60417 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60418 Roo.log(e.toString());
60423 var vs = t.target ? t.target.call(this, values, parent) : values;
60424 parent = t.target ? values : parent;
60425 if(t.target && vs instanceof Array){
60427 for(var i = 0, len = vs.length; i < len; i++){
60428 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60430 return buf.join('');
60432 return t.compiled.call(this, vs, parent);
60434 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60435 Roo.log(e.toString());
60436 Roo.log(t.compiled);
60441 compileTpl : function(tpl)
60443 var fm = Roo.util.Format;
60444 var useF = this.disableFormats !== true;
60445 var sep = Roo.isGecko ? "+" : ",";
60446 var undef = function(str) {
60447 Roo.log("Property not found :" + str);
60451 var fn = function(m, name, format, args)
60453 //Roo.log(arguments);
60454 args = args ? args.replace(/\\'/g,"'") : args;
60455 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60456 if (typeof(format) == 'undefined') {
60457 format= 'htmlEncode';
60459 if (format == 'raw' ) {
60463 if(name.substr(0, 4) == 'xtpl'){
60464 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60467 // build an array of options to determine if value is undefined..
60469 // basically get 'xxxx.yyyy' then do
60470 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60471 // (function () { Roo.log("Property not found"); return ''; })() :
60476 Roo.each(name.split('.'), function(st) {
60477 lookfor += (lookfor.length ? '.': '') + st;
60478 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60481 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60484 if(format && useF){
60486 args = args ? ',' + args : "";
60488 if(format.substr(0, 5) != "this."){
60489 format = "fm." + format + '(';
60491 format = 'this.call("'+ format.substr(5) + '", ';
60495 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60499 // called with xxyx.yuu:(test,test)
60501 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60503 // raw.. - :raw modifier..
60504 return "'"+ sep + udef_st + name + ")"+sep+"'";
60508 // branched to use + in gecko and [].join() in others
60510 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60511 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60514 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60515 body.push(tpl.body.replace(/(\r\n|\n)/g,
60516 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60517 body.push("'].join('');};};");
60518 body = body.join('');
60521 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60523 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60529 applyTemplate : function(values){
60530 return this.master.compiled.call(this, values, {});
60531 //var s = this.subs;
60534 apply : function(){
60535 return this.applyTemplate.apply(this, arguments);
60540 Roo.XTemplate.from = function(el){
60541 el = Roo.getDom(el);
60542 return new Roo.XTemplate(el.value || el.innerHTML);