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 alert(Roo.isAndroid);
7200 alert('Is Android');
7201 return Roo.get(document.documentElement);
7205 alert('not android');
7208 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7212 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7213 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7214 * @param {String} selector The simple selector to test
7215 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7216 search as a number or element (defaults to 10 || document.body)
7217 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7219 up : function(simpleSelector, maxDepth){
7220 return this.findParentNode(simpleSelector, maxDepth, true);
7226 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7227 * @param {String} selector The simple selector to test
7228 * @return {Boolean} True if this element matches the selector, else false
7230 is : function(simpleSelector){
7231 return Roo.DomQuery.is(this.dom, simpleSelector);
7235 * Perform animation on this element.
7236 * @param {Object} args The YUI animation control args
7237 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7238 * @param {Function} onComplete (optional) Function to call when animation completes
7239 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7240 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7241 * @return {Roo.Element} this
7243 animate : function(args, duration, onComplete, easing, animType){
7244 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7249 * @private Internal animation call
7251 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7252 animType = animType || 'run';
7254 var anim = Roo.lib.Anim[animType](
7256 (opt.duration || defaultDur) || .35,
7257 (opt.easing || defaultEase) || 'easeOut',
7259 Roo.callback(cb, this);
7260 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7268 // private legacy anim prep
7269 preanim : function(a, i){
7270 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7274 * Removes worthless text nodes
7275 * @param {Boolean} forceReclean (optional) By default the element
7276 * keeps track if it has been cleaned already so
7277 * you can call this over and over. However, if you update the element and
7278 * need to force a reclean, you can pass true.
7280 clean : function(forceReclean){
7281 if(this.isCleaned && forceReclean !== true){
7285 var d = this.dom, n = d.firstChild, ni = -1;
7287 var nx = n.nextSibling;
7288 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7295 this.isCleaned = true;
7300 calcOffsetsTo : function(el){
7303 var restorePos = false;
7304 if(el.getStyle('position') == 'static'){
7305 el.position('relative');
7310 while(op && op != d && op.tagName != 'HTML'){
7313 op = op.offsetParent;
7316 el.position('static');
7322 * Scrolls this element into view within the passed container.
7323 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7324 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7325 * @return {Roo.Element} this
7327 scrollIntoView : function(container, hscroll){
7328 var c = Roo.getDom(container) || document.body;
7331 var o = this.calcOffsetsTo(c),
7334 b = t+el.offsetHeight,
7335 r = l+el.offsetWidth;
7337 var ch = c.clientHeight;
7338 var ct = parseInt(c.scrollTop, 10);
7339 var cl = parseInt(c.scrollLeft, 10);
7341 var cr = cl + c.clientWidth;
7349 if(hscroll !== false){
7353 c.scrollLeft = r-c.clientWidth;
7360 scrollChildIntoView : function(child, hscroll){
7361 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7365 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7366 * the new height may not be available immediately.
7367 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7368 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7369 * @param {Function} onComplete (optional) Function to call when animation completes
7370 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7371 * @return {Roo.Element} this
7373 autoHeight : function(animate, duration, onComplete, easing){
7374 var oldHeight = this.getHeight();
7376 this.setHeight(1); // force clipping
7377 setTimeout(function(){
7378 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7380 this.setHeight(height);
7382 if(typeof onComplete == "function"){
7386 this.setHeight(oldHeight); // restore original height
7387 this.setHeight(height, animate, duration, function(){
7389 if(typeof onComplete == "function") { onComplete(); }
7390 }.createDelegate(this), easing);
7392 }.createDelegate(this), 0);
7397 * Returns true if this element is an ancestor of the passed element
7398 * @param {HTMLElement/String} el The element to check
7399 * @return {Boolean} True if this element is an ancestor of el, else false
7401 contains : function(el){
7402 if(!el){return false;}
7403 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7407 * Checks whether the element is currently visible using both visibility and display properties.
7408 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7409 * @return {Boolean} True if the element is currently visible, else false
7411 isVisible : function(deep) {
7412 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7413 if(deep !== true || !vis){
7416 var p = this.dom.parentNode;
7417 while(p && p.tagName.toLowerCase() != "body"){
7418 if(!Roo.fly(p, '_isVisible').isVisible()){
7427 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7428 * @param {String} selector The CSS selector
7429 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7430 * @return {CompositeElement/CompositeElementLite} The composite element
7432 select : function(selector, unique){
7433 return El.select(selector, unique, this.dom);
7437 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7438 * @param {String} selector The CSS selector
7439 * @return {Array} An array of the matched nodes
7441 query : function(selector, unique){
7442 return Roo.DomQuery.select(selector, this.dom);
7446 * Selects a single child at any depth below this element 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 child : function(selector, returnDom){
7452 var n = Roo.DomQuery.selectNode(selector, this.dom);
7453 return returnDom ? n : Roo.get(n);
7457 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7458 * @param {String} selector The CSS selector
7459 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7460 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7462 down : function(selector, returnDom){
7463 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7464 return returnDom ? n : Roo.get(n);
7468 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7469 * @param {String} group The group the DD object is member of
7470 * @param {Object} config The DD config object
7471 * @param {Object} overrides An object containing methods to override/implement on the DD object
7472 * @return {Roo.dd.DD} The DD object
7474 initDD : function(group, config, overrides){
7475 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7476 return Roo.apply(dd, overrides);
7480 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7481 * @param {String} group The group the DDProxy object is member of
7482 * @param {Object} config The DDProxy config object
7483 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7484 * @return {Roo.dd.DDProxy} The DDProxy object
7486 initDDProxy : function(group, config, overrides){
7487 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7488 return Roo.apply(dd, overrides);
7492 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7493 * @param {String} group The group the DDTarget object is member of
7494 * @param {Object} config The DDTarget config object
7495 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7496 * @return {Roo.dd.DDTarget} The DDTarget object
7498 initDDTarget : function(group, config, overrides){
7499 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7500 return Roo.apply(dd, overrides);
7504 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7505 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7506 * @param {Boolean} visible Whether the element is visible
7507 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7508 * @return {Roo.Element} this
7510 setVisible : function(visible, animate){
7512 if(this.visibilityMode == El.DISPLAY){
7513 this.setDisplayed(visible);
7516 this.dom.style.visibility = visible ? "visible" : "hidden";
7519 // closure for composites
7521 var visMode = this.visibilityMode;
7523 this.setOpacity(.01);
7524 this.setVisible(true);
7526 this.anim({opacity: { to: (visible?1:0) }},
7527 this.preanim(arguments, 1),
7528 null, .35, 'easeIn', function(){
7530 if(visMode == El.DISPLAY){
7531 dom.style.display = "none";
7533 dom.style.visibility = "hidden";
7535 Roo.get(dom).setOpacity(1);
7543 * Returns true if display is not "none"
7546 isDisplayed : function() {
7547 return this.getStyle("display") != "none";
7551 * Toggles the element's visibility or display, depending on visibility mode.
7552 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7553 * @return {Roo.Element} this
7555 toggle : function(animate){
7556 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7561 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7562 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7563 * @return {Roo.Element} this
7565 setDisplayed : function(value) {
7566 if(typeof value == "boolean"){
7567 value = value ? this.originalDisplay : "none";
7569 this.setStyle("display", value);
7574 * Tries to focus the element. Any exceptions are caught and ignored.
7575 * @return {Roo.Element} this
7577 focus : function() {
7585 * Tries to blur the element. Any exceptions are caught and ignored.
7586 * @return {Roo.Element} this
7596 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7597 * @param {String/Array} className The CSS class to add, or an array of classes
7598 * @return {Roo.Element} this
7600 addClass : function(className){
7601 if(className instanceof Array){
7602 for(var i = 0, len = className.length; i < len; i++) {
7603 this.addClass(className[i]);
7606 if(className && !this.hasClass(className)){
7607 this.dom.className = this.dom.className + " " + className;
7614 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7615 * @param {String/Array} className The CSS class to add, or an array of classes
7616 * @return {Roo.Element} this
7618 radioClass : function(className){
7619 var siblings = this.dom.parentNode.childNodes;
7620 for(var i = 0; i < siblings.length; i++) {
7621 var s = siblings[i];
7622 if(s.nodeType == 1){
7623 Roo.get(s).removeClass(className);
7626 this.addClass(className);
7631 * Removes one or more CSS classes from the element.
7632 * @param {String/Array} className The CSS class to remove, or an array of classes
7633 * @return {Roo.Element} this
7635 removeClass : function(className){
7636 if(!className || !this.dom.className){
7639 if(className instanceof Array){
7640 for(var i = 0, len = className.length; i < len; i++) {
7641 this.removeClass(className[i]);
7644 if(this.hasClass(className)){
7645 var re = this.classReCache[className];
7647 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7648 this.classReCache[className] = re;
7650 this.dom.className =
7651 this.dom.className.replace(re, " ");
7661 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7662 * @param {String} className The CSS class to toggle
7663 * @return {Roo.Element} this
7665 toggleClass : function(className){
7666 if(this.hasClass(className)){
7667 this.removeClass(className);
7669 this.addClass(className);
7675 * Checks if the specified CSS class exists on this element's DOM node.
7676 * @param {String} className The CSS class to check for
7677 * @return {Boolean} True if the class exists, else false
7679 hasClass : function(className){
7680 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7684 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7685 * @param {String} oldClassName The CSS class to replace
7686 * @param {String} newClassName The replacement CSS class
7687 * @return {Roo.Element} this
7689 replaceClass : function(oldClassName, newClassName){
7690 this.removeClass(oldClassName);
7691 this.addClass(newClassName);
7696 * Returns an object with properties matching the styles requested.
7697 * For example, el.getStyles('color', 'font-size', 'width') might return
7698 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7699 * @param {String} style1 A style name
7700 * @param {String} style2 A style name
7701 * @param {String} etc.
7702 * @return {Object} The style object
7704 getStyles : function(){
7705 var a = arguments, len = a.length, r = {};
7706 for(var i = 0; i < len; i++){
7707 r[a[i]] = this.getStyle(a[i]);
7713 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7714 * @param {String} property The style property whose value is returned.
7715 * @return {String} The current value of the style property for this element.
7717 getStyle : function(){
7718 return view && view.getComputedStyle ?
7720 var el = this.dom, v, cs, camel;
7721 if(prop == 'float'){
7724 if(el.style && (v = el.style[prop])){
7727 if(cs = view.getComputedStyle(el, "")){
7728 if(!(camel = propCache[prop])){
7729 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7736 var el = this.dom, v, cs, camel;
7737 if(prop == 'opacity'){
7738 if(typeof el.style.filter == 'string'){
7739 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7741 var fv = parseFloat(m[1]);
7743 return fv ? fv / 100 : 0;
7748 }else if(prop == 'float'){
7749 prop = "styleFloat";
7751 if(!(camel = propCache[prop])){
7752 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7754 if(v = el.style[camel]){
7757 if(cs = el.currentStyle){
7765 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7766 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7767 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7768 * @return {Roo.Element} this
7770 setStyle : function(prop, value){
7771 if(typeof prop == "string"){
7773 if (prop == 'float') {
7774 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7779 if(!(camel = propCache[prop])){
7780 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7783 if(camel == 'opacity') {
7784 this.setOpacity(value);
7786 this.dom.style[camel] = value;
7789 for(var style in prop){
7790 if(typeof prop[style] != "function"){
7791 this.setStyle(style, prop[style]);
7799 * More flexible version of {@link #setStyle} for setting style properties.
7800 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7801 * a function which returns such a specification.
7802 * @return {Roo.Element} this
7804 applyStyles : function(style){
7805 Roo.DomHelper.applyStyles(this.dom, style);
7810 * 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).
7811 * @return {Number} The X position of the element
7814 return D.getX(this.dom);
7818 * 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).
7819 * @return {Number} The Y position of the element
7822 return D.getY(this.dom);
7826 * 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).
7827 * @return {Array} The XY position of the element
7830 return D.getXY(this.dom);
7834 * 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).
7835 * @param {Number} The X position of the element
7836 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7837 * @return {Roo.Element} this
7839 setX : function(x, animate){
7841 D.setX(this.dom, x);
7843 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7849 * 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).
7850 * @param {Number} The Y position of the element
7851 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7852 * @return {Roo.Element} this
7854 setY : function(y, animate){
7856 D.setY(this.dom, y);
7858 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7864 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7865 * @param {String} left The left CSS property value
7866 * @return {Roo.Element} this
7868 setLeft : function(left){
7869 this.setStyle("left", this.addUnits(left));
7874 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7875 * @param {String} top The top CSS property value
7876 * @return {Roo.Element} this
7878 setTop : function(top){
7879 this.setStyle("top", this.addUnits(top));
7884 * Sets the element's CSS right style.
7885 * @param {String} right The right CSS property value
7886 * @return {Roo.Element} this
7888 setRight : function(right){
7889 this.setStyle("right", this.addUnits(right));
7894 * Sets the element's CSS bottom style.
7895 * @param {String} bottom The bottom CSS property value
7896 * @return {Roo.Element} this
7898 setBottom : function(bottom){
7899 this.setStyle("bottom", this.addUnits(bottom));
7904 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7905 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7906 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7907 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7908 * @return {Roo.Element} this
7910 setXY : function(pos, animate){
7912 D.setXY(this.dom, pos);
7914 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7920 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7921 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7922 * @param {Number} x X value for new position (coordinates are page-based)
7923 * @param {Number} y Y value for new position (coordinates are page-based)
7924 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7925 * @return {Roo.Element} this
7927 setLocation : function(x, y, animate){
7928 this.setXY([x, y], this.preanim(arguments, 2));
7933 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7934 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7935 * @param {Number} x X value for new position (coordinates are page-based)
7936 * @param {Number} y Y value for new position (coordinates are page-based)
7937 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 moveTo : function(x, y, animate){
7941 this.setXY([x, y], this.preanim(arguments, 2));
7946 * Returns the region of the given element.
7947 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7948 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7950 getRegion : function(){
7951 return D.getRegion(this.dom);
7955 * Returns the offset height of the element
7956 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7957 * @return {Number} The element's height
7959 getHeight : function(contentHeight){
7960 var h = this.dom.offsetHeight || 0;
7961 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7965 * Returns the offset width of the element
7966 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7967 * @return {Number} The element's width
7969 getWidth : function(contentWidth){
7970 var w = this.dom.offsetWidth || 0;
7971 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7975 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7976 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7977 * if a height has not been set using CSS.
7980 getComputedHeight : function(){
7981 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7983 h = parseInt(this.getStyle('height'), 10) || 0;
7984 if(!this.isBorderBox()){
7985 h += this.getFrameWidth('tb');
7992 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7993 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7994 * if a width has not been set using CSS.
7997 getComputedWidth : function(){
7998 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8000 w = parseInt(this.getStyle('width'), 10) || 0;
8001 if(!this.isBorderBox()){
8002 w += this.getFrameWidth('lr');
8009 * Returns the size of the element.
8010 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8011 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8013 getSize : function(contentSize){
8014 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8018 * Returns the width and height of the viewport.
8019 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8021 getViewSize : function(){
8022 var d = this.dom, doc = document, aw = 0, ah = 0;
8023 if(d == doc || d == doc.body){
8024 return {width : D.getViewWidth(), height: D.getViewHeight()};
8027 width : d.clientWidth,
8028 height: d.clientHeight
8034 * Returns the value of the "value" attribute
8035 * @param {Boolean} asNumber true to parse the value as a number
8036 * @return {String/Number}
8038 getValue : function(asNumber){
8039 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8043 adjustWidth : function(width){
8044 if(typeof width == "number"){
8045 if(this.autoBoxAdjust && !this.isBorderBox()){
8046 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8056 adjustHeight : function(height){
8057 if(typeof height == "number"){
8058 if(this.autoBoxAdjust && !this.isBorderBox()){
8059 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8069 * Set the width of the element
8070 * @param {Number} width The new width
8071 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8072 * @return {Roo.Element} this
8074 setWidth : function(width, animate){
8075 width = this.adjustWidth(width);
8077 this.dom.style.width = this.addUnits(width);
8079 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8085 * Set the height of the element
8086 * @param {Number} height The new height
8087 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8088 * @return {Roo.Element} this
8090 setHeight : function(height, animate){
8091 height = this.adjustHeight(height);
8093 this.dom.style.height = this.addUnits(height);
8095 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8101 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8102 * @param {Number} width The new width
8103 * @param {Number} height The new height
8104 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8105 * @return {Roo.Element} this
8107 setSize : function(width, height, animate){
8108 if(typeof width == "object"){ // in case of object from getSize()
8109 height = width.height; width = width.width;
8111 width = this.adjustWidth(width); height = this.adjustHeight(height);
8113 this.dom.style.width = this.addUnits(width);
8114 this.dom.style.height = this.addUnits(height);
8116 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8122 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8123 * @param {Number} x X value for new position (coordinates are page-based)
8124 * @param {Number} y Y value for new position (coordinates are page-based)
8125 * @param {Number} width The new width
8126 * @param {Number} height The new height
8127 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8128 * @return {Roo.Element} this
8130 setBounds : function(x, y, width, height, animate){
8132 this.setSize(width, height);
8133 this.setLocation(x, y);
8135 width = this.adjustWidth(width); height = this.adjustHeight(height);
8136 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8137 this.preanim(arguments, 4), 'motion');
8143 * 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.
8144 * @param {Roo.lib.Region} region The region to fill
8145 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8146 * @return {Roo.Element} this
8148 setRegion : function(region, animate){
8149 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8154 * Appends an event handler
8156 * @param {String} eventName The type of event to append
8157 * @param {Function} fn The method the event invokes
8158 * @param {Object} scope (optional) The scope (this object) of the fn
8159 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8161 addListener : function(eventName, fn, scope, options){
8163 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8168 * Removes an event handler from this element
8169 * @param {String} eventName the type of event to remove
8170 * @param {Function} fn the method the event invokes
8171 * @return {Roo.Element} this
8173 removeListener : function(eventName, fn){
8174 Roo.EventManager.removeListener(this.dom, eventName, fn);
8179 * Removes all previous added listeners from this element
8180 * @return {Roo.Element} this
8182 removeAllListeners : function(){
8183 E.purgeElement(this.dom);
8187 relayEvent : function(eventName, observable){
8188 this.on(eventName, function(e){
8189 observable.fireEvent(eventName, e);
8194 * Set the opacity of the element
8195 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8196 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8197 * @return {Roo.Element} this
8199 setOpacity : function(opacity, animate){
8201 var s = this.dom.style;
8204 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8205 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8207 s.opacity = opacity;
8210 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8216 * Gets the left X coordinate
8217 * @param {Boolean} local True to get the local css position instead of page coordinate
8220 getLeft : function(local){
8224 return parseInt(this.getStyle("left"), 10) || 0;
8229 * Gets the right X coordinate of the element (element X position + element width)
8230 * @param {Boolean} local True to get the local css position instead of page coordinate
8233 getRight : function(local){
8235 return this.getX() + this.getWidth();
8237 return (this.getLeft(true) + this.getWidth()) || 0;
8242 * Gets the top Y coordinate
8243 * @param {Boolean} local True to get the local css position instead of page coordinate
8246 getTop : function(local) {
8250 return parseInt(this.getStyle("top"), 10) || 0;
8255 * Gets the bottom Y coordinate of the element (element Y position + element height)
8256 * @param {Boolean} local True to get the local css position instead of page coordinate
8259 getBottom : function(local){
8261 return this.getY() + this.getHeight();
8263 return (this.getTop(true) + this.getHeight()) || 0;
8268 * Initializes positioning on this element. If a desired position is not passed, it will make the
8269 * the element positioned relative IF it is not already positioned.
8270 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8271 * @param {Number} zIndex (optional) The zIndex to apply
8272 * @param {Number} x (optional) Set the page X position
8273 * @param {Number} y (optional) Set the page Y position
8275 position : function(pos, zIndex, x, y){
8277 if(this.getStyle('position') == 'static'){
8278 this.setStyle('position', 'relative');
8281 this.setStyle("position", pos);
8284 this.setStyle("z-index", zIndex);
8286 if(x !== undefined && y !== undefined){
8288 }else if(x !== undefined){
8290 }else if(y !== undefined){
8296 * Clear positioning back to the default when the document was loaded
8297 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8298 * @return {Roo.Element} this
8300 clearPositioning : function(value){
8308 "position" : "static"
8314 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8315 * snapshot before performing an update and then restoring the element.
8318 getPositioning : function(){
8319 var l = this.getStyle("left");
8320 var t = this.getStyle("top");
8322 "position" : this.getStyle("position"),
8324 "right" : l ? "" : this.getStyle("right"),
8326 "bottom" : t ? "" : this.getStyle("bottom"),
8327 "z-index" : this.getStyle("z-index")
8332 * Gets the width of the border(s) for the specified side(s)
8333 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8334 * passing lr would get the border (l)eft width + the border (r)ight width.
8335 * @return {Number} The width of the sides passed added together
8337 getBorderWidth : function(side){
8338 return this.addStyles(side, El.borders);
8342 * Gets the width of the padding(s) for the specified side(s)
8343 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8344 * passing lr would get the padding (l)eft + the padding (r)ight.
8345 * @return {Number} The padding of the sides passed added together
8347 getPadding : function(side){
8348 return this.addStyles(side, El.paddings);
8352 * Set positioning with an object returned by getPositioning().
8353 * @param {Object} posCfg
8354 * @return {Roo.Element} this
8356 setPositioning : function(pc){
8357 this.applyStyles(pc);
8358 if(pc.right == "auto"){
8359 this.dom.style.right = "";
8361 if(pc.bottom == "auto"){
8362 this.dom.style.bottom = "";
8368 fixDisplay : function(){
8369 if(this.getStyle("display") == "none"){
8370 this.setStyle("visibility", "hidden");
8371 this.setStyle("display", this.originalDisplay); // first try reverting to default
8372 if(this.getStyle("display") == "none"){ // if that fails, default to block
8373 this.setStyle("display", "block");
8379 * Quick set left and top adding default units
8380 * @param {String} left The left CSS property value
8381 * @param {String} top The top CSS property value
8382 * @return {Roo.Element} this
8384 setLeftTop : function(left, top){
8385 this.dom.style.left = this.addUnits(left);
8386 this.dom.style.top = this.addUnits(top);
8391 * Move this element relative to its current position.
8392 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8393 * @param {Number} distance How far to move the element in pixels
8394 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8395 * @return {Roo.Element} this
8397 move : function(direction, distance, animate){
8398 var xy = this.getXY();
8399 direction = direction.toLowerCase();
8403 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8407 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8412 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8417 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8424 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8425 * @return {Roo.Element} this
8428 if(!this.isClipped){
8429 this.isClipped = true;
8430 this.originalClip = {
8431 "o": this.getStyle("overflow"),
8432 "x": this.getStyle("overflow-x"),
8433 "y": this.getStyle("overflow-y")
8435 this.setStyle("overflow", "hidden");
8436 this.setStyle("overflow-x", "hidden");
8437 this.setStyle("overflow-y", "hidden");
8443 * Return clipping (overflow) to original clipping before clip() was called
8444 * @return {Roo.Element} this
8446 unclip : function(){
8448 this.isClipped = false;
8449 var o = this.originalClip;
8450 if(o.o){this.setStyle("overflow", o.o);}
8451 if(o.x){this.setStyle("overflow-x", o.x);}
8452 if(o.y){this.setStyle("overflow-y", o.y);}
8459 * Gets the x,y coordinates specified by the anchor position on the element.
8460 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8461 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8462 * {width: (target width), height: (target height)} (defaults to the element's current size)
8463 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8464 * @return {Array} [x, y] An array containing the element's x and y coordinates
8466 getAnchorXY : function(anchor, local, s){
8467 //Passing a different size is useful for pre-calculating anchors,
8468 //especially for anchored animations that change the el size.
8470 var w, h, vp = false;
8473 if(d == document.body || d == document){
8475 w = D.getViewWidth(); h = D.getViewHeight();
8477 w = this.getWidth(); h = this.getHeight();
8480 w = s.width; h = s.height;
8482 var x = 0, y = 0, r = Math.round;
8483 switch((anchor || "tl").toLowerCase()){
8525 var sc = this.getScroll();
8526 return [x + sc.left, y + sc.top];
8528 //Add the element's offset xy
8529 var o = this.getXY();
8530 return [x+o[0], y+o[1]];
8534 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8535 * supported position values.
8536 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8537 * @param {String} position The position to align to.
8538 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8539 * @return {Array} [x, y]
8541 getAlignToXY : function(el, p, o){
8545 throw "Element.alignTo with an element that doesn't exist";
8547 var c = false; //constrain to viewport
8548 var p1 = "", p2 = "";
8555 }else if(p.indexOf("-") == -1){
8558 p = p.toLowerCase();
8559 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8561 throw "Element.alignTo with an invalid alignment " + p;
8563 p1 = m[1]; p2 = m[2]; c = !!m[3];
8565 //Subtract the aligned el's internal xy from the target's offset xy
8566 //plus custom offset to get the aligned el's new offset xy
8567 var a1 = this.getAnchorXY(p1, true);
8568 var a2 = el.getAnchorXY(p2, false);
8569 var x = a2[0] - a1[0] + o[0];
8570 var y = a2[1] - a1[1] + o[1];
8572 //constrain the aligned el to viewport if necessary
8573 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8574 // 5px of margin for ie
8575 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8577 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8578 //perpendicular to the vp border, allow the aligned el to slide on that border,
8579 //otherwise swap the aligned el to the opposite border of the target.
8580 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8581 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8582 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8583 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8586 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8587 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8589 if((x+w) > dw + scrollX){
8590 x = swapX ? r.left-w : dw+scrollX-w;
8593 x = swapX ? r.right : scrollX;
8595 if((y+h) > dh + scrollY){
8596 y = swapY ? r.top-h : dh+scrollY-h;
8599 y = swapY ? r.bottom : scrollY;
8606 getConstrainToXY : function(){
8607 var os = {top:0, left:0, bottom:0, right: 0};
8609 return function(el, local, offsets, proposedXY){
8611 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8613 var vw, vh, vx = 0, vy = 0;
8614 if(el.dom == document.body || el.dom == document){
8615 vw = Roo.lib.Dom.getViewWidth();
8616 vh = Roo.lib.Dom.getViewHeight();
8618 vw = el.dom.clientWidth;
8619 vh = el.dom.clientHeight;
8621 var vxy = el.getXY();
8627 var s = el.getScroll();
8629 vx += offsets.left + s.left;
8630 vy += offsets.top + s.top;
8632 vw -= offsets.right;
8633 vh -= offsets.bottom;
8638 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8639 var x = xy[0], y = xy[1];
8640 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8642 // only move it if it needs it
8645 // first validate right/bottom
8654 // then make sure top/left isn't negative
8663 return moved ? [x, y] : false;
8668 adjustForConstraints : function(xy, parent, offsets){
8669 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8673 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8674 * document it aligns it to the viewport.
8675 * The position parameter is optional, and can be specified in any one of the following formats:
8677 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8678 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8679 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8680 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8681 * <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
8682 * element's anchor point, and the second value is used as the target's anchor point.</li>
8684 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8685 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8686 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8687 * that specified in order to enforce the viewport constraints.
8688 * Following are all of the supported anchor positions:
8691 ----- -----------------------------
8692 tl The top left corner (default)
8693 t The center of the top edge
8694 tr The top right corner
8695 l The center of the left edge
8696 c In the center of the element
8697 r The center of the right edge
8698 bl The bottom left corner
8699 b The center of the bottom edge
8700 br The bottom right corner
8704 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8705 el.alignTo("other-el");
8707 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8708 el.alignTo("other-el", "tr?");
8710 // align the bottom right corner of el with the center left edge of other-el
8711 el.alignTo("other-el", "br-l?");
8713 // align the center of el with the bottom left corner of other-el and
8714 // adjust the x position by -6 pixels (and the y position by 0)
8715 el.alignTo("other-el", "c-bl", [-6, 0]);
8717 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8718 * @param {String} position The position to align to.
8719 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8720 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8721 * @return {Roo.Element} this
8723 alignTo : function(element, position, offsets, animate){
8724 var xy = this.getAlignToXY(element, position, offsets);
8725 this.setXY(xy, this.preanim(arguments, 3));
8730 * Anchors an element to another element and realigns it when the window is resized.
8731 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8732 * @param {String} position The position to align to.
8733 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8734 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8735 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8736 * is a number, it is used as the buffer delay (defaults to 50ms).
8737 * @param {Function} callback The function to call after the animation finishes
8738 * @return {Roo.Element} this
8740 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8741 var action = function(){
8742 this.alignTo(el, alignment, offsets, animate);
8743 Roo.callback(callback, this);
8745 Roo.EventManager.onWindowResize(action, this);
8746 var tm = typeof monitorScroll;
8747 if(tm != 'undefined'){
8748 Roo.EventManager.on(window, 'scroll', action, this,
8749 {buffer: tm == 'number' ? monitorScroll : 50});
8751 action.call(this); // align immediately
8755 * Clears any opacity settings from this element. Required in some cases for IE.
8756 * @return {Roo.Element} this
8758 clearOpacity : function(){
8759 if (window.ActiveXObject) {
8760 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8761 this.dom.style.filter = "";
8764 this.dom.style.opacity = "";
8765 this.dom.style["-moz-opacity"] = "";
8766 this.dom.style["-khtml-opacity"] = "";
8772 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8773 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8774 * @return {Roo.Element} this
8776 hide : function(animate){
8777 this.setVisible(false, this.preanim(arguments, 0));
8782 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8783 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8784 * @return {Roo.Element} this
8786 show : function(animate){
8787 this.setVisible(true, this.preanim(arguments, 0));
8792 * @private Test if size has a unit, otherwise appends the default
8794 addUnits : function(size){
8795 return Roo.Element.addUnits(size, this.defaultUnit);
8799 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8800 * @return {Roo.Element} this
8802 beginMeasure : function(){
8804 if(el.offsetWidth || el.offsetHeight){
8805 return this; // offsets work already
8808 var p = this.dom, b = document.body; // start with this element
8809 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8810 var pe = Roo.get(p);
8811 if(pe.getStyle('display') == 'none'){
8812 changed.push({el: p, visibility: pe.getStyle("visibility")});
8813 p.style.visibility = "hidden";
8814 p.style.display = "block";
8818 this._measureChanged = changed;
8824 * Restores displays to before beginMeasure was called
8825 * @return {Roo.Element} this
8827 endMeasure : function(){
8828 var changed = this._measureChanged;
8830 for(var i = 0, len = changed.length; i < len; i++) {
8832 r.el.style.visibility = r.visibility;
8833 r.el.style.display = "none";
8835 this._measureChanged = null;
8841 * Update the innerHTML of this element, optionally searching for and processing scripts
8842 * @param {String} html The new HTML
8843 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8844 * @param {Function} callback For async script loading you can be noticed when the update completes
8845 * @return {Roo.Element} this
8847 update : function(html, loadScripts, callback){
8848 if(typeof html == "undefined"){
8851 if(loadScripts !== true){
8852 this.dom.innerHTML = html;
8853 if(typeof callback == "function"){
8861 html += '<span id="' + id + '"></span>';
8863 E.onAvailable(id, function(){
8864 var hd = document.getElementsByTagName("head")[0];
8865 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8866 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8867 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8870 while(match = re.exec(html)){
8871 var attrs = match[1];
8872 var srcMatch = attrs ? attrs.match(srcRe) : false;
8873 if(srcMatch && srcMatch[2]){
8874 var s = document.createElement("script");
8875 s.src = srcMatch[2];
8876 var typeMatch = attrs.match(typeRe);
8877 if(typeMatch && typeMatch[2]){
8878 s.type = typeMatch[2];
8881 }else if(match[2] && match[2].length > 0){
8882 if(window.execScript) {
8883 window.execScript(match[2]);
8891 window.eval(match[2]);
8895 var el = document.getElementById(id);
8896 if(el){el.parentNode.removeChild(el);}
8897 if(typeof callback == "function"){
8901 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8906 * Direct access to the UpdateManager update() method (takes the same parameters).
8907 * @param {String/Function} url The url for this request or a function to call to get the url
8908 * @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}
8909 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8910 * @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.
8911 * @return {Roo.Element} this
8914 var um = this.getUpdateManager();
8915 um.update.apply(um, arguments);
8920 * Gets this element's UpdateManager
8921 * @return {Roo.UpdateManager} The UpdateManager
8923 getUpdateManager : function(){
8924 if(!this.updateManager){
8925 this.updateManager = new Roo.UpdateManager(this);
8927 return this.updateManager;
8931 * Disables text selection for this element (normalized across browsers)
8932 * @return {Roo.Element} this
8934 unselectable : function(){
8935 this.dom.unselectable = "on";
8936 this.swallowEvent("selectstart", true);
8937 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8938 this.addClass("x-unselectable");
8943 * Calculates the x, y to center this element on the screen
8944 * @return {Array} The x, y values [x, y]
8946 getCenterXY : function(){
8947 return this.getAlignToXY(document, 'c-c');
8951 * Centers the Element in either the viewport, or another Element.
8952 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8954 center : function(centerIn){
8955 this.alignTo(centerIn || document, 'c-c');
8960 * Tests various css rules/browsers to determine if this element uses a border box
8963 isBorderBox : function(){
8964 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8968 * Return a box {x, y, width, height} that can be used to set another elements
8969 * size/location to match this element.
8970 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8971 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8972 * @return {Object} box An object in the format {x, y, width, height}
8974 getBox : function(contentBox, local){
8979 var left = parseInt(this.getStyle("left"), 10) || 0;
8980 var top = parseInt(this.getStyle("top"), 10) || 0;
8983 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8985 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8987 var l = this.getBorderWidth("l")+this.getPadding("l");
8988 var r = this.getBorderWidth("r")+this.getPadding("r");
8989 var t = this.getBorderWidth("t")+this.getPadding("t");
8990 var b = this.getBorderWidth("b")+this.getPadding("b");
8991 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)};
8993 bx.right = bx.x + bx.width;
8994 bx.bottom = bx.y + bx.height;
8999 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9000 for more information about the sides.
9001 * @param {String} sides
9004 getFrameWidth : function(sides, onlyContentBox){
9005 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9009 * 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.
9010 * @param {Object} box The box to fill {x, y, width, height}
9011 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9012 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9013 * @return {Roo.Element} this
9015 setBox : function(box, adjust, animate){
9016 var w = box.width, h = box.height;
9017 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9018 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9019 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9021 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9026 * Forces the browser to repaint this element
9027 * @return {Roo.Element} this
9029 repaint : function(){
9031 this.addClass("x-repaint");
9032 setTimeout(function(){
9033 Roo.get(dom).removeClass("x-repaint");
9039 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9040 * then it returns the calculated width of the sides (see getPadding)
9041 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9042 * @return {Object/Number}
9044 getMargins : function(side){
9047 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9048 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9049 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9050 right: parseInt(this.getStyle("margin-right"), 10) || 0
9053 return this.addStyles(side, El.margins);
9058 addStyles : function(sides, styles){
9060 for(var i = 0, len = sides.length; i < len; i++){
9061 v = this.getStyle(styles[sides.charAt(i)]);
9063 w = parseInt(v, 10);
9071 * Creates a proxy element of this element
9072 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9073 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9074 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9075 * @return {Roo.Element} The new proxy element
9077 createProxy : function(config, renderTo, matchBox){
9079 renderTo = Roo.getDom(renderTo);
9081 renderTo = document.body;
9083 config = typeof config == "object" ?
9084 config : {tag : "div", cls: config};
9085 var proxy = Roo.DomHelper.append(renderTo, config, true);
9087 proxy.setBox(this.getBox());
9093 * Puts a mask over this element to disable user interaction. Requires core.css.
9094 * This method can only be applied to elements which accept child nodes.
9095 * @param {String} msg (optional) A message to display in the mask
9096 * @param {String} msgCls (optional) A css class to apply to the msg element
9097 * @return {Element} The mask element
9099 mask : function(msg, msgCls)
9101 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9102 this.setStyle("position", "relative");
9105 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9107 this.addClass("x-masked");
9108 this._mask.setDisplayed(true);
9113 while (dom && dom.style) {
9114 if (!isNaN(parseInt(dom.style.zIndex))) {
9115 z = Math.max(z, parseInt(dom.style.zIndex));
9117 dom = dom.parentNode;
9119 // if we are masking the body - then it hides everything..
9120 if (this.dom == document.body) {
9122 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9123 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9126 if(typeof msg == 'string'){
9128 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9130 var mm = this._maskMsg;
9131 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9132 if (mm.dom.firstChild) { // weird IE issue?
9133 mm.dom.firstChild.innerHTML = msg;
9135 mm.setDisplayed(true);
9137 mm.setStyle('z-index', z + 102);
9139 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9140 this._mask.setHeight(this.getHeight());
9142 this._mask.setStyle('z-index', z + 100);
9148 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9149 * it is cached for reuse.
9151 unmask : function(removeEl){
9153 if(removeEl === true){
9154 this._mask.remove();
9157 this._maskMsg.remove();
9158 delete this._maskMsg;
9161 this._mask.setDisplayed(false);
9163 this._maskMsg.setDisplayed(false);
9167 this.removeClass("x-masked");
9171 * Returns true if this element is masked
9174 isMasked : function(){
9175 return this._mask && this._mask.isVisible();
9179 * Creates an iframe shim for this element to keep selects and other windowed objects from
9181 * @return {Roo.Element} The new shim element
9183 createShim : function(){
9184 var el = document.createElement('iframe');
9185 el.frameBorder = 'no';
9186 el.className = 'roo-shim';
9187 if(Roo.isIE && Roo.isSecure){
9188 el.src = Roo.SSL_SECURE_URL;
9190 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9191 shim.autoBoxAdjust = false;
9196 * Removes this element from the DOM and deletes it from the cache
9198 remove : function(){
9199 if(this.dom.parentNode){
9200 this.dom.parentNode.removeChild(this.dom);
9202 delete El.cache[this.dom.id];
9206 * Sets up event handlers to add and remove a css class when the mouse is over this element
9207 * @param {String} className
9208 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9209 * mouseout events for children elements
9210 * @return {Roo.Element} this
9212 addClassOnOver : function(className, preventFlicker){
9213 this.on("mouseover", function(){
9214 Roo.fly(this, '_internal').addClass(className);
9216 var removeFn = function(e){
9217 if(preventFlicker !== true || !e.within(this, true)){
9218 Roo.fly(this, '_internal').removeClass(className);
9221 this.on("mouseout", removeFn, this.dom);
9226 * Sets up event handlers to add and remove a css class when this element has the focus
9227 * @param {String} className
9228 * @return {Roo.Element} this
9230 addClassOnFocus : function(className){
9231 this.on("focus", function(){
9232 Roo.fly(this, '_internal').addClass(className);
9234 this.on("blur", function(){
9235 Roo.fly(this, '_internal').removeClass(className);
9240 * 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)
9241 * @param {String} className
9242 * @return {Roo.Element} this
9244 addClassOnClick : function(className){
9246 this.on("mousedown", function(){
9247 Roo.fly(dom, '_internal').addClass(className);
9248 var d = Roo.get(document);
9249 var fn = function(){
9250 Roo.fly(dom, '_internal').removeClass(className);
9251 d.removeListener("mouseup", fn);
9253 d.on("mouseup", fn);
9259 * Stops the specified event from bubbling and optionally prevents the default action
9260 * @param {String} eventName
9261 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9262 * @return {Roo.Element} this
9264 swallowEvent : function(eventName, preventDefault){
9265 var fn = function(e){
9266 e.stopPropagation();
9271 if(eventName instanceof Array){
9272 for(var i = 0, len = eventName.length; i < len; i++){
9273 this.on(eventName[i], fn);
9277 this.on(eventName, fn);
9284 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9287 * Sizes this element to its parent element's dimensions performing
9288 * neccessary box adjustments.
9289 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9290 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9291 * @return {Roo.Element} this
9293 fitToParent : function(monitorResize, targetParent) {
9294 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9295 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9296 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9299 var p = Roo.get(targetParent || this.dom.parentNode);
9300 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9301 if (monitorResize === true) {
9302 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9303 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9309 * Gets the next sibling, skipping text nodes
9310 * @return {HTMLElement} The next sibling or null
9312 getNextSibling : function(){
9313 var n = this.dom.nextSibling;
9314 while(n && n.nodeType != 1){
9321 * Gets the previous sibling, skipping text nodes
9322 * @return {HTMLElement} The previous sibling or null
9324 getPrevSibling : function(){
9325 var n = this.dom.previousSibling;
9326 while(n && n.nodeType != 1){
9327 n = n.previousSibling;
9334 * Appends the passed element(s) to this element
9335 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9336 * @return {Roo.Element} this
9338 appendChild: function(el){
9345 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9346 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9347 * automatically generated with the specified attributes.
9348 * @param {HTMLElement} insertBefore (optional) a child element of this element
9349 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9350 * @return {Roo.Element} The new child element
9352 createChild: function(config, insertBefore, returnDom){
9353 config = config || {tag:'div'};
9355 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9357 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9361 * Appends this element to the passed element
9362 * @param {String/HTMLElement/Element} el The new parent element
9363 * @return {Roo.Element} this
9365 appendTo: function(el){
9366 el = Roo.getDom(el);
9367 el.appendChild(this.dom);
9372 * Inserts this element before the passed element in the DOM
9373 * @param {String/HTMLElement/Element} el The element to insert before
9374 * @return {Roo.Element} this
9376 insertBefore: function(el){
9377 el = Roo.getDom(el);
9378 el.parentNode.insertBefore(this.dom, el);
9383 * Inserts this element after the passed element in the DOM
9384 * @param {String/HTMLElement/Element} el The element to insert after
9385 * @return {Roo.Element} this
9387 insertAfter: function(el){
9388 el = Roo.getDom(el);
9389 el.parentNode.insertBefore(this.dom, el.nextSibling);
9394 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9395 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9396 * @return {Roo.Element} The new child
9398 insertFirst: function(el, returnDom){
9400 if(typeof el == 'object' && !el.nodeType){ // dh config
9401 return this.createChild(el, this.dom.firstChild, returnDom);
9403 el = Roo.getDom(el);
9404 this.dom.insertBefore(el, this.dom.firstChild);
9405 return !returnDom ? Roo.get(el) : el;
9410 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9411 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9412 * @param {String} where (optional) 'before' or 'after' defaults to before
9413 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9414 * @return {Roo.Element} the inserted Element
9416 insertSibling: function(el, where, returnDom){
9417 where = where ? where.toLowerCase() : 'before';
9419 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9421 if(typeof el == 'object' && !el.nodeType){ // dh config
9422 if(where == 'after' && !this.dom.nextSibling){
9423 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9425 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9429 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9430 where == 'before' ? this.dom : this.dom.nextSibling);
9439 * Creates and wraps this element with another element
9440 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9441 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9442 * @return {HTMLElement/Element} The newly created wrapper element
9444 wrap: function(config, returnDom){
9446 config = {tag: "div"};
9448 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9449 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9454 * Replaces the passed element with this element
9455 * @param {String/HTMLElement/Element} el The element to replace
9456 * @return {Roo.Element} this
9458 replace: function(el){
9460 this.insertBefore(el);
9466 * Inserts an html fragment into this element
9467 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9468 * @param {String} html The HTML fragment
9469 * @param {Boolean} returnEl True to return an Roo.Element
9470 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9472 insertHtml : function(where, html, returnEl){
9473 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9474 return returnEl ? Roo.get(el) : el;
9478 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9479 * @param {Object} o The object with the attributes
9480 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9481 * @return {Roo.Element} this
9483 set : function(o, useSet){
9485 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9487 if(attr == "style" || typeof o[attr] == "function") { continue; }
9489 el.className = o["cls"];
9492 el.setAttribute(attr, o[attr]);
9499 Roo.DomHelper.applyStyles(el, o.style);
9505 * Convenience method for constructing a KeyMap
9506 * @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:
9507 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9508 * @param {Function} fn The function to call
9509 * @param {Object} scope (optional) The scope of the function
9510 * @return {Roo.KeyMap} The KeyMap created
9512 addKeyListener : function(key, fn, scope){
9514 if(typeof key != "object" || key instanceof Array){
9530 return new Roo.KeyMap(this, config);
9534 * Creates a KeyMap for this element
9535 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9536 * @return {Roo.KeyMap} The KeyMap created
9538 addKeyMap : function(config){
9539 return new Roo.KeyMap(this, config);
9543 * Returns true if this element is scrollable.
9546 isScrollable : function(){
9548 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9552 * 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().
9553 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9554 * @param {Number} value The new scroll value
9555 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9556 * @return {Element} this
9559 scrollTo : function(side, value, animate){
9560 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9562 this.dom[prop] = value;
9564 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9565 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9571 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9572 * within this element's scrollable range.
9573 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9574 * @param {Number} distance How far to scroll the element in pixels
9575 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9576 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9577 * was scrolled as far as it could go.
9579 scroll : function(direction, distance, animate){
9580 if(!this.isScrollable()){
9584 var l = el.scrollLeft, t = el.scrollTop;
9585 var w = el.scrollWidth, h = el.scrollHeight;
9586 var cw = el.clientWidth, ch = el.clientHeight;
9587 direction = direction.toLowerCase();
9588 var scrolled = false;
9589 var a = this.preanim(arguments, 2);
9594 var v = Math.min(l + distance, w-cw);
9595 this.scrollTo("left", v, a);
9602 var v = Math.max(l - distance, 0);
9603 this.scrollTo("left", v, a);
9611 var v = Math.max(t - distance, 0);
9612 this.scrollTo("top", v, a);
9620 var v = Math.min(t + distance, h-ch);
9621 this.scrollTo("top", v, a);
9630 * Translates the passed page coordinates into left/top css values for this element
9631 * @param {Number/Array} x The page x or an array containing [x, y]
9632 * @param {Number} y The page y
9633 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9635 translatePoints : function(x, y){
9636 if(typeof x == 'object' || x instanceof Array){
9639 var p = this.getStyle('position');
9640 var o = this.getXY();
9642 var l = parseInt(this.getStyle('left'), 10);
9643 var t = parseInt(this.getStyle('top'), 10);
9646 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9649 t = (p == "relative") ? 0 : this.dom.offsetTop;
9652 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9656 * Returns the current scroll position of the element.
9657 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9659 getScroll : function(){
9660 var d = this.dom, doc = document;
9661 if(d == doc || d == doc.body){
9662 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9663 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9664 return {left: l, top: t};
9666 return {left: d.scrollLeft, top: d.scrollTop};
9671 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9672 * are convert to standard 6 digit hex color.
9673 * @param {String} attr The css attribute
9674 * @param {String} defaultValue The default value to use when a valid color isn't found
9675 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9678 getColor : function(attr, defaultValue, prefix){
9679 var v = this.getStyle(attr);
9680 if(!v || v == "transparent" || v == "inherit") {
9681 return defaultValue;
9683 var color = typeof prefix == "undefined" ? "#" : prefix;
9684 if(v.substr(0, 4) == "rgb("){
9685 var rvs = v.slice(4, v.length -1).split(",");
9686 for(var i = 0; i < 3; i++){
9687 var h = parseInt(rvs[i]).toString(16);
9694 if(v.substr(0, 1) == "#"){
9696 for(var i = 1; i < 4; i++){
9697 var c = v.charAt(i);
9700 }else if(v.length == 7){
9701 color += v.substr(1);
9705 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9709 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9710 * gradient background, rounded corners and a 4-way shadow.
9711 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9712 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9713 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9714 * @return {Roo.Element} this
9716 boxWrap : function(cls){
9717 cls = cls || 'x-box';
9718 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9719 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9724 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9725 * @param {String} namespace The namespace in which to look for the attribute
9726 * @param {String} name The attribute name
9727 * @return {String} The attribute value
9729 getAttributeNS : Roo.isIE ? function(ns, name){
9731 var type = typeof d[ns+":"+name];
9732 if(type != 'undefined' && type != 'unknown'){
9733 return d[ns+":"+name];
9736 } : function(ns, name){
9738 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9743 * Sets or Returns the value the dom attribute value
9744 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9745 * @param {String} value (optional) The value to set the attribute to
9746 * @return {String} The attribute value
9748 attr : function(name){
9749 if (arguments.length > 1) {
9750 this.dom.setAttribute(name, arguments[1]);
9751 return arguments[1];
9753 if (typeof(name) == 'object') {
9754 for(var i in name) {
9755 this.attr(i, name[i]);
9761 if (!this.dom.hasAttribute(name)) {
9764 return this.dom.getAttribute(name);
9771 var ep = El.prototype;
9774 * Appends an event handler (Shorthand for addListener)
9775 * @param {String} eventName The type of event to append
9776 * @param {Function} fn The method the event invokes
9777 * @param {Object} scope (optional) The scope (this object) of the fn
9778 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9781 ep.on = ep.addListener;
9783 ep.mon = ep.addListener;
9786 * Removes an event handler from this element (shorthand for removeListener)
9787 * @param {String} eventName the type of event to remove
9788 * @param {Function} fn the method the event invokes
9789 * @return {Roo.Element} this
9792 ep.un = ep.removeListener;
9795 * true to automatically adjust width and height settings for box-model issues (default to true)
9797 ep.autoBoxAdjust = true;
9800 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9803 El.addUnits = function(v, defaultUnit){
9804 if(v === "" || v == "auto"){
9807 if(v === undefined){
9810 if(typeof v == "number" || !El.unitPattern.test(v)){
9811 return v + (defaultUnit || 'px');
9816 // special markup used throughout Roo when box wrapping elements
9817 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>';
9819 * Visibility mode constant - Use visibility to hide element
9825 * Visibility mode constant - Use display to hide element
9831 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9832 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9833 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9845 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9846 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9847 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9848 * @return {Element} The Element object
9851 El.get = function(el){
9853 if(!el){ return null; }
9854 if(typeof el == "string"){ // element id
9855 if(!(elm = document.getElementById(el))){
9858 if(ex = El.cache[el]){
9861 ex = El.cache[el] = new El(elm);
9864 }else if(el.tagName){ // dom element
9868 if(ex = El.cache[id]){
9871 ex = El.cache[id] = new El(el);
9874 }else if(el instanceof El){
9876 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9877 // catch case where it hasn't been appended
9878 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9881 }else if(el.isComposite){
9883 }else if(el instanceof Array){
9884 return El.select(el);
9885 }else if(el == document){
9886 // create a bogus element object representing the document object
9888 var f = function(){};
9889 f.prototype = El.prototype;
9891 docEl.dom = document;
9899 El.uncache = function(el){
9900 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9902 delete El.cache[a[i].id || a[i]];
9908 // Garbage collection - uncache elements/purge listeners on orphaned elements
9909 // so we don't hold a reference and cause the browser to retain them
9910 El.garbageCollect = function(){
9911 if(!Roo.enableGarbageCollector){
9912 clearInterval(El.collectorThread);
9915 for(var eid in El.cache){
9916 var el = El.cache[eid], d = el.dom;
9917 // -------------------------------------------------------
9918 // Determining what is garbage:
9919 // -------------------------------------------------------
9921 // dom node is null, definitely garbage
9922 // -------------------------------------------------------
9924 // no parentNode == direct orphan, definitely garbage
9925 // -------------------------------------------------------
9926 // !d.offsetParent && !document.getElementById(eid)
9927 // display none elements have no offsetParent so we will
9928 // also try to look it up by it's id. However, check
9929 // offsetParent first so we don't do unneeded lookups.
9930 // This enables collection of elements that are not orphans
9931 // directly, but somewhere up the line they have an orphan
9933 // -------------------------------------------------------
9934 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9935 delete El.cache[eid];
9936 if(d && Roo.enableListenerCollection){
9942 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9946 El.Flyweight = function(dom){
9949 El.Flyweight.prototype = El.prototype;
9951 El._flyweights = {};
9953 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9954 * the dom node can be overwritten by other code.
9955 * @param {String/HTMLElement} el The dom node or id
9956 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9957 * prevent conflicts (e.g. internally Roo uses "_internal")
9959 * @return {Element} The shared Element object
9961 El.fly = function(el, named){
9962 named = named || '_global';
9963 el = Roo.getDom(el);
9967 if(!El._flyweights[named]){
9968 El._flyweights[named] = new El.Flyweight();
9970 El._flyweights[named].dom = el;
9971 return El._flyweights[named];
9975 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9976 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9977 * Shorthand of {@link Roo.Element#get}
9978 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9979 * @return {Element} The Element object
9985 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9986 * the dom node can be overwritten by other code.
9987 * Shorthand of {@link Roo.Element#fly}
9988 * @param {String/HTMLElement} el The dom node or id
9989 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9990 * prevent conflicts (e.g. internally Roo uses "_internal")
9992 * @return {Element} The shared Element object
9998 // speedy lookup for elements never to box adjust
9999 var noBoxAdjust = Roo.isStrict ? {
10002 input:1, select:1, textarea:1
10004 if(Roo.isIE || Roo.isGecko){
10005 noBoxAdjust['button'] = 1;
10009 Roo.EventManager.on(window, 'unload', function(){
10011 delete El._flyweights;
10019 Roo.Element.selectorFunction = Roo.DomQuery.select;
10022 Roo.Element.select = function(selector, unique, root){
10024 if(typeof selector == "string"){
10025 els = Roo.Element.selectorFunction(selector, root);
10026 }else if(selector.length !== undefined){
10029 throw "Invalid selector";
10031 if(unique === true){
10032 return new Roo.CompositeElement(els);
10034 return new Roo.CompositeElementLite(els);
10038 * Selects elements based on the passed CSS selector to enable working on them as 1.
10039 * @param {String/Array} selector The CSS selector or an array of elements
10040 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10041 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10042 * @return {CompositeElementLite/CompositeElement}
10046 Roo.select = Roo.Element.select;
10063 * Ext JS Library 1.1.1
10064 * Copyright(c) 2006-2007, Ext JS, LLC.
10066 * Originally Released Under LGPL - original licence link has changed is not relivant.
10069 * <script type="text/javascript">
10074 //Notifies Element that fx methods are available
10075 Roo.enableFx = true;
10079 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10080 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10081 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10082 * Element effects to work.</p><br/>
10084 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10085 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10086 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10087 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10088 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10089 * expected results and should be done with care.</p><br/>
10091 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10092 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10095 ----- -----------------------------
10096 tl The top left corner
10097 t The center of the top edge
10098 tr The top right corner
10099 l The center of the left edge
10100 r The center of the right edge
10101 bl The bottom left corner
10102 b The center of the bottom edge
10103 br The bottom right corner
10105 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10106 * below are common options that can be passed to any Fx method.</b>
10107 * @cfg {Function} callback A function called when the effect is finished
10108 * @cfg {Object} scope The scope of the effect function
10109 * @cfg {String} easing A valid Easing value for the effect
10110 * @cfg {String} afterCls A css class to apply after the effect
10111 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10112 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10113 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10114 * effects that end with the element being visually hidden, ignored otherwise)
10115 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10116 * a function which returns such a specification that will be applied to the Element after the effect finishes
10117 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10118 * @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
10119 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10123 * Slides the element into view. An anchor point can be optionally passed to set the point of
10124 * origin for the slide effect. This function automatically handles wrapping the element with
10125 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10128 // default: slide the element in from the top
10131 // custom: slide the element in from the right with a 2-second duration
10132 el.slideIn('r', { duration: 2 });
10134 // common config options shown with default values
10140 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10141 * @param {Object} options (optional) Object literal with any of the Fx config options
10142 * @return {Roo.Element} The Element
10144 slideIn : function(anchor, o){
10145 var el = this.getFxEl();
10148 el.queueFx(o, function(){
10150 anchor = anchor || "t";
10152 // fix display to visibility
10155 // restore values after effect
10156 var r = this.getFxRestore();
10157 var b = this.getBox();
10158 // fixed size for slide
10162 var wrap = this.fxWrap(r.pos, o, "hidden");
10164 var st = this.dom.style;
10165 st.visibility = "visible";
10166 st.position = "absolute";
10168 // clear out temp styles after slide and unwrap
10169 var after = function(){
10170 el.fxUnwrap(wrap, r.pos, o);
10171 st.width = r.width;
10172 st.height = r.height;
10175 // time to calc the positions
10176 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10178 switch(anchor.toLowerCase()){
10180 wrap.setSize(b.width, 0);
10181 st.left = st.bottom = "0";
10185 wrap.setSize(0, b.height);
10186 st.right = st.top = "0";
10190 wrap.setSize(0, b.height);
10191 wrap.setX(b.right);
10192 st.left = st.top = "0";
10193 a = {width: bw, points: pt};
10196 wrap.setSize(b.width, 0);
10197 wrap.setY(b.bottom);
10198 st.left = st.top = "0";
10199 a = {height: bh, points: pt};
10202 wrap.setSize(0, 0);
10203 st.right = st.bottom = "0";
10204 a = {width: bw, height: bh};
10207 wrap.setSize(0, 0);
10208 wrap.setY(b.y+b.height);
10209 st.right = st.top = "0";
10210 a = {width: bw, height: bh, points: pt};
10213 wrap.setSize(0, 0);
10214 wrap.setXY([b.right, b.bottom]);
10215 st.left = st.top = "0";
10216 a = {width: bw, height: bh, points: pt};
10219 wrap.setSize(0, 0);
10220 wrap.setX(b.x+b.width);
10221 st.left = st.bottom = "0";
10222 a = {width: bw, height: bh, points: pt};
10225 this.dom.style.visibility = "visible";
10228 arguments.callee.anim = wrap.fxanim(a,
10238 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10239 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10240 * 'hidden') but block elements will still take up space in the document. The element must be removed
10241 * from the DOM using the 'remove' config option if desired. This function automatically handles
10242 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10245 // default: slide the element out to the top
10248 // custom: slide the element out to the right with a 2-second duration
10249 el.slideOut('r', { duration: 2 });
10251 // common config options shown with default values
10259 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10260 * @param {Object} options (optional) Object literal with any of the Fx config options
10261 * @return {Roo.Element} The Element
10263 slideOut : function(anchor, o){
10264 var el = this.getFxEl();
10267 el.queueFx(o, function(){
10269 anchor = anchor || "t";
10271 // restore values after effect
10272 var r = this.getFxRestore();
10274 var b = this.getBox();
10275 // fixed size for slide
10279 var wrap = this.fxWrap(r.pos, o, "visible");
10281 var st = this.dom.style;
10282 st.visibility = "visible";
10283 st.position = "absolute";
10287 var after = function(){
10289 el.setDisplayed(false);
10294 el.fxUnwrap(wrap, r.pos, o);
10296 st.width = r.width;
10297 st.height = r.height;
10302 var a, zero = {to: 0};
10303 switch(anchor.toLowerCase()){
10305 st.left = st.bottom = "0";
10306 a = {height: zero};
10309 st.right = st.top = "0";
10313 st.left = st.top = "0";
10314 a = {width: zero, points: {to:[b.right, b.y]}};
10317 st.left = st.top = "0";
10318 a = {height: zero, points: {to:[b.x, b.bottom]}};
10321 st.right = st.bottom = "0";
10322 a = {width: zero, height: zero};
10325 st.right = st.top = "0";
10326 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10329 st.left = st.top = "0";
10330 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10333 st.left = st.bottom = "0";
10334 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10338 arguments.callee.anim = wrap.fxanim(a,
10348 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10349 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10350 * The element must be removed from the DOM using the 'remove' config option if desired.
10356 // common config options shown with default values
10364 * @param {Object} options (optional) Object literal with any of the Fx config options
10365 * @return {Roo.Element} The Element
10367 puff : function(o){
10368 var el = this.getFxEl();
10371 el.queueFx(o, function(){
10372 this.clearOpacity();
10375 // restore values after effect
10376 var r = this.getFxRestore();
10377 var st = this.dom.style;
10379 var after = function(){
10381 el.setDisplayed(false);
10388 el.setPositioning(r.pos);
10389 st.width = r.width;
10390 st.height = r.height;
10395 var width = this.getWidth();
10396 var height = this.getHeight();
10398 arguments.callee.anim = this.fxanim({
10399 width : {to: this.adjustWidth(width * 2)},
10400 height : {to: this.adjustHeight(height * 2)},
10401 points : {by: [-(width * .5), -(height * .5)]},
10403 fontSize: {to:200, unit: "%"}
10414 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10415 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10416 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10422 // all config options shown with default values
10430 * @param {Object} options (optional) Object literal with any of the Fx config options
10431 * @return {Roo.Element} The Element
10433 switchOff : function(o){
10434 var el = this.getFxEl();
10437 el.queueFx(o, function(){
10438 this.clearOpacity();
10441 // restore values after effect
10442 var r = this.getFxRestore();
10443 var st = this.dom.style;
10445 var after = function(){
10447 el.setDisplayed(false);
10453 el.setPositioning(r.pos);
10454 st.width = r.width;
10455 st.height = r.height;
10460 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10461 this.clearOpacity();
10465 points:{by:[0, this.getHeight() * .5]}
10466 }, o, 'motion', 0.3, 'easeIn', after);
10467 }).defer(100, this);
10474 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10475 * changed using the "attr" config option) and then fading back to the original color. If no original
10476 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10479 // default: highlight background to yellow
10482 // custom: highlight foreground text to blue for 2 seconds
10483 el.highlight("0000ff", { attr: 'color', duration: 2 });
10485 // common config options shown with default values
10486 el.highlight("ffff9c", {
10487 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10488 endColor: (current color) or "ffffff",
10493 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10494 * @param {Object} options (optional) Object literal with any of the Fx config options
10495 * @return {Roo.Element} The Element
10497 highlight : function(color, o){
10498 var el = this.getFxEl();
10501 el.queueFx(o, function(){
10502 color = color || "ffff9c";
10503 attr = o.attr || "backgroundColor";
10505 this.clearOpacity();
10508 var origColor = this.getColor(attr);
10509 var restoreColor = this.dom.style[attr];
10510 endColor = (o.endColor || origColor) || "ffffff";
10512 var after = function(){
10513 el.dom.style[attr] = restoreColor;
10518 a[attr] = {from: color, to: endColor};
10519 arguments.callee.anim = this.fxanim(a,
10529 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10532 // default: a single light blue ripple
10535 // custom: 3 red ripples lasting 3 seconds total
10536 el.frame("ff0000", 3, { duration: 3 });
10538 // common config options shown with default values
10539 el.frame("C3DAF9", 1, {
10540 duration: 1 //duration of entire animation (not each individual ripple)
10541 // Note: Easing is not configurable and will be ignored if included
10544 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10545 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10546 * @param {Object} options (optional) Object literal with any of the Fx config options
10547 * @return {Roo.Element} The Element
10549 frame : function(color, count, o){
10550 var el = this.getFxEl();
10553 el.queueFx(o, function(){
10554 color = color || "#C3DAF9";
10555 if(color.length == 6){
10556 color = "#" + color;
10558 count = count || 1;
10559 duration = o.duration || 1;
10562 var b = this.getBox();
10563 var animFn = function(){
10564 var proxy = this.createProxy({
10567 visbility:"hidden",
10568 position:"absolute",
10569 "z-index":"35000", // yee haw
10570 border:"0px solid " + color
10573 var scale = Roo.isBorderBox ? 2 : 1;
10575 top:{from:b.y, to:b.y - 20},
10576 left:{from:b.x, to:b.x - 20},
10577 borderWidth:{from:0, to:10},
10578 opacity:{from:1, to:0},
10579 height:{from:b.height, to:(b.height + (20*scale))},
10580 width:{from:b.width, to:(b.width + (20*scale))}
10581 }, duration, function(){
10585 animFn.defer((duration/2)*1000, this);
10596 * Creates a pause before any subsequent queued effects begin. If there are
10597 * no effects queued after the pause it will have no effect.
10602 * @param {Number} seconds The length of time to pause (in seconds)
10603 * @return {Roo.Element} The Element
10605 pause : function(seconds){
10606 var el = this.getFxEl();
10609 el.queueFx(o, function(){
10610 setTimeout(function(){
10612 }, seconds * 1000);
10618 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10619 * using the "endOpacity" config option.
10622 // default: fade in from opacity 0 to 100%
10625 // custom: fade in from opacity 0 to 75% over 2 seconds
10626 el.fadeIn({ endOpacity: .75, duration: 2});
10628 // common config options shown with default values
10630 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10635 * @param {Object} options (optional) Object literal with any of the Fx config options
10636 * @return {Roo.Element} The Element
10638 fadeIn : function(o){
10639 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 this.setOpacity(0);
10644 this.dom.style.visibility = 'visible';
10645 var to = o.endOpacity || 1;
10646 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10647 o, null, .5, "easeOut", function(){
10649 this.clearOpacity();
10658 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10659 * using the "endOpacity" config option.
10662 // default: fade out from the element's current opacity to 0
10665 // custom: fade out from the element's current opacity to 25% over 2 seconds
10666 el.fadeOut({ endOpacity: .25, duration: 2});
10668 // common config options shown with default values
10670 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10677 * @param {Object} options (optional) Object literal with any of the Fx config options
10678 * @return {Roo.Element} The Element
10680 fadeOut : function(o){
10681 var el = this.getFxEl();
10683 el.queueFx(o, function(){
10684 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10685 o, null, .5, "easeOut", function(){
10686 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10687 this.dom.style.display = "none";
10689 this.dom.style.visibility = "hidden";
10691 this.clearOpacity();
10699 * Animates the transition of an element's dimensions from a starting height/width
10700 * to an ending height/width.
10703 // change height and width to 100x100 pixels
10704 el.scale(100, 100);
10706 // common config options shown with default values. The height and width will default to
10707 // the element's existing values if passed as null.
10710 [element's height], {
10715 * @param {Number} width The new width (pass undefined to keep the original width)
10716 * @param {Number} height The new height (pass undefined to keep the original height)
10717 * @param {Object} options (optional) Object literal with any of the Fx config options
10718 * @return {Roo.Element} The Element
10720 scale : function(w, h, o){
10721 this.shift(Roo.apply({}, o, {
10729 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10730 * Any of these properties not specified in the config object will not be changed. This effect
10731 * requires that at least one new dimension, position or opacity setting must be passed in on
10732 * the config object in order for the function to have any effect.
10735 // slide the element horizontally to x position 200 while changing the height and opacity
10736 el.shift({ x: 200, height: 50, opacity: .8 });
10738 // common config options shown with default values.
10740 width: [element's width],
10741 height: [element's height],
10742 x: [element's x position],
10743 y: [element's y position],
10744 opacity: [element's opacity],
10749 * @param {Object} options Object literal with any of the Fx config options
10750 * @return {Roo.Element} The Element
10752 shift : function(o){
10753 var el = this.getFxEl();
10755 el.queueFx(o, function(){
10756 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10757 if(w !== undefined){
10758 a.width = {to: this.adjustWidth(w)};
10760 if(h !== undefined){
10761 a.height = {to: this.adjustHeight(h)};
10763 if(x !== undefined || y !== undefined){
10765 x !== undefined ? x : this.getX(),
10766 y !== undefined ? y : this.getY()
10769 if(op !== undefined){
10770 a.opacity = {to: op};
10772 if(o.xy !== undefined){
10773 a.points = {to: o.xy};
10775 arguments.callee.anim = this.fxanim(a,
10776 o, 'motion', .35, "easeOut", function(){
10784 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10785 * ending point of the effect.
10788 // default: slide the element downward while fading out
10791 // custom: slide the element out to the right with a 2-second duration
10792 el.ghost('r', { duration: 2 });
10794 // common config options shown with default values
10802 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10803 * @param {Object} options (optional) Object literal with any of the Fx config options
10804 * @return {Roo.Element} The Element
10806 ghost : function(anchor, o){
10807 var el = this.getFxEl();
10810 el.queueFx(o, function(){
10811 anchor = anchor || "b";
10813 // restore values after effect
10814 var r = this.getFxRestore();
10815 var w = this.getWidth(),
10816 h = this.getHeight();
10818 var st = this.dom.style;
10820 var after = function(){
10822 el.setDisplayed(false);
10828 el.setPositioning(r.pos);
10829 st.width = r.width;
10830 st.height = r.height;
10835 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10836 switch(anchor.toLowerCase()){
10863 arguments.callee.anim = this.fxanim(a,
10873 * Ensures that all effects queued after syncFx is called on the element are
10874 * run concurrently. This is the opposite of {@link #sequenceFx}.
10875 * @return {Roo.Element} The Element
10877 syncFx : function(){
10878 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10887 * Ensures that all effects queued after sequenceFx is called on the element are
10888 * run in sequence. This is the opposite of {@link #syncFx}.
10889 * @return {Roo.Element} The Element
10891 sequenceFx : function(){
10892 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10894 concurrent : false,
10901 nextFx : function(){
10902 var ef = this.fxQueue[0];
10909 * Returns true if the element has any effects actively running or queued, else returns false.
10910 * @return {Boolean} True if element has active effects, else false
10912 hasActiveFx : function(){
10913 return this.fxQueue && this.fxQueue[0];
10917 * Stops any running effects and clears the element's internal effects queue if it contains
10918 * any additional effects that haven't started yet.
10919 * @return {Roo.Element} The Element
10921 stopFx : function(){
10922 if(this.hasActiveFx()){
10923 var cur = this.fxQueue[0];
10924 if(cur && cur.anim && cur.anim.isAnimated()){
10925 this.fxQueue = [cur]; // clear out others
10926 cur.anim.stop(true);
10933 beforeFx : function(o){
10934 if(this.hasActiveFx() && !o.concurrent){
10945 * Returns true if the element is currently blocking so that no other effect can be queued
10946 * until this effect is finished, else returns false if blocking is not set. This is commonly
10947 * used to ensure that an effect initiated by a user action runs to completion prior to the
10948 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10949 * @return {Boolean} True if blocking, else false
10951 hasFxBlock : function(){
10952 var q = this.fxQueue;
10953 return q && q[0] && q[0].block;
10957 queueFx : function(o, fn){
10961 if(!this.hasFxBlock()){
10962 Roo.applyIf(o, this.fxDefaults);
10964 var run = this.beforeFx(o);
10965 fn.block = o.block;
10966 this.fxQueue.push(fn);
10978 fxWrap : function(pos, o, vis){
10980 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10983 wrapXY = this.getXY();
10985 var div = document.createElement("div");
10986 div.style.visibility = vis;
10987 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10988 wrap.setPositioning(pos);
10989 if(wrap.getStyle("position") == "static"){
10990 wrap.position("relative");
10992 this.clearPositioning('auto');
10994 wrap.dom.appendChild(this.dom);
10996 wrap.setXY(wrapXY);
11003 fxUnwrap : function(wrap, pos, o){
11004 this.clearPositioning();
11005 this.setPositioning(pos);
11007 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11013 getFxRestore : function(){
11014 var st = this.dom.style;
11015 return {pos: this.getPositioning(), width: st.width, height : st.height};
11019 afterFx : function(o){
11021 this.applyStyles(o.afterStyle);
11024 this.addClass(o.afterCls);
11026 if(o.remove === true){
11029 Roo.callback(o.callback, o.scope, [this]);
11031 this.fxQueue.shift();
11037 getFxEl : function(){ // support for composite element fx
11038 return Roo.get(this.dom);
11042 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11043 animType = animType || 'run';
11045 var anim = Roo.lib.Anim[animType](
11047 (opt.duration || defaultDur) || .35,
11048 (opt.easing || defaultEase) || 'easeOut',
11050 Roo.callback(cb, this);
11059 // backwords compat
11060 Roo.Fx.resize = Roo.Fx.scale;
11062 //When included, Roo.Fx is automatically applied to Element so that all basic
11063 //effects are available directly via the Element API
11064 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11066 * Ext JS Library 1.1.1
11067 * Copyright(c) 2006-2007, Ext JS, LLC.
11069 * Originally Released Under LGPL - original licence link has changed is not relivant.
11072 * <script type="text/javascript">
11077 * @class Roo.CompositeElement
11078 * Standard composite class. Creates a Roo.Element for every element in the collection.
11080 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11081 * actions will be performed on all the elements in this collection.</b>
11083 * All methods return <i>this</i> and can be chained.
11085 var els = Roo.select("#some-el div.some-class", true);
11086 // or select directly from an existing element
11087 var el = Roo.get('some-el');
11088 el.select('div.some-class', true);
11090 els.setWidth(100); // all elements become 100 width
11091 els.hide(true); // all elements fade out and hide
11093 els.setWidth(100).hide(true);
11096 Roo.CompositeElement = function(els){
11097 this.elements = [];
11098 this.addElements(els);
11100 Roo.CompositeElement.prototype = {
11102 addElements : function(els){
11106 if(typeof els == "string"){
11107 els = Roo.Element.selectorFunction(els);
11109 var yels = this.elements;
11110 var index = yels.length-1;
11111 for(var i = 0, len = els.length; i < len; i++) {
11112 yels[++index] = Roo.get(els[i]);
11118 * Clears this composite and adds the elements returned by the passed selector.
11119 * @param {String/Array} els A string CSS selector, an array of elements or an element
11120 * @return {CompositeElement} this
11122 fill : function(els){
11123 this.elements = [];
11129 * Filters this composite to only elements that match the passed selector.
11130 * @param {String} selector A string CSS selector
11131 * @param {Boolean} inverse return inverse filter (not matches)
11132 * @return {CompositeElement} this
11134 filter : function(selector, inverse){
11136 inverse = inverse || false;
11137 this.each(function(el){
11138 var match = inverse ? !el.is(selector) : el.is(selector);
11140 els[els.length] = el.dom;
11147 invoke : function(fn, args){
11148 var els = this.elements;
11149 for(var i = 0, len = els.length; i < len; i++) {
11150 Roo.Element.prototype[fn].apply(els[i], args);
11155 * Adds elements to this composite.
11156 * @param {String/Array} els A string CSS selector, an array of elements or an element
11157 * @return {CompositeElement} this
11159 add : function(els){
11160 if(typeof els == "string"){
11161 this.addElements(Roo.Element.selectorFunction(els));
11162 }else if(els.length !== undefined){
11163 this.addElements(els);
11165 this.addElements([els]);
11170 * Calls the passed function passing (el, this, index) for each element in this composite.
11171 * @param {Function} fn The function to call
11172 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11173 * @return {CompositeElement} this
11175 each : function(fn, scope){
11176 var els = this.elements;
11177 for(var i = 0, len = els.length; i < len; i++){
11178 if(fn.call(scope || els[i], els[i], this, i) === false) {
11186 * Returns the Element object at the specified index
11187 * @param {Number} index
11188 * @return {Roo.Element}
11190 item : function(index){
11191 return this.elements[index] || null;
11195 * Returns the first Element
11196 * @return {Roo.Element}
11198 first : function(){
11199 return this.item(0);
11203 * Returns the last Element
11204 * @return {Roo.Element}
11207 return this.item(this.elements.length-1);
11211 * Returns the number of elements in this composite
11214 getCount : function(){
11215 return this.elements.length;
11219 * Returns true if this composite contains the passed element
11222 contains : function(el){
11223 return this.indexOf(el) !== -1;
11227 * Returns true if this composite contains the passed element
11230 indexOf : function(el){
11231 return this.elements.indexOf(Roo.get(el));
11236 * Removes the specified element(s).
11237 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11238 * or an array of any of those.
11239 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11240 * @return {CompositeElement} this
11242 removeElement : function(el, removeDom){
11243 if(el instanceof Array){
11244 for(var i = 0, len = el.length; i < len; i++){
11245 this.removeElement(el[i]);
11249 var index = typeof el == 'number' ? el : this.indexOf(el);
11252 var d = this.elements[index];
11256 d.parentNode.removeChild(d);
11259 this.elements.splice(index, 1);
11265 * Replaces the specified element with the passed element.
11266 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11268 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11269 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11270 * @return {CompositeElement} this
11272 replaceElement : function(el, replacement, domReplace){
11273 var index = typeof el == 'number' ? el : this.indexOf(el);
11276 this.elements[index].replaceWith(replacement);
11278 this.elements.splice(index, 1, Roo.get(replacement))
11285 * Removes all elements.
11287 clear : function(){
11288 this.elements = [];
11292 Roo.CompositeElement.createCall = function(proto, fnName){
11293 if(!proto[fnName]){
11294 proto[fnName] = function(){
11295 return this.invoke(fnName, arguments);
11299 for(var fnName in Roo.Element.prototype){
11300 if(typeof Roo.Element.prototype[fnName] == "function"){
11301 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11307 * Ext JS Library 1.1.1
11308 * Copyright(c) 2006-2007, Ext JS, LLC.
11310 * Originally Released Under LGPL - original licence link has changed is not relivant.
11313 * <script type="text/javascript">
11317 * @class Roo.CompositeElementLite
11318 * @extends Roo.CompositeElement
11319 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11321 var els = Roo.select("#some-el div.some-class");
11322 // or select directly from an existing element
11323 var el = Roo.get('some-el');
11324 el.select('div.some-class');
11326 els.setWidth(100); // all elements become 100 width
11327 els.hide(true); // all elements fade out and hide
11329 els.setWidth(100).hide(true);
11330 </code></pre><br><br>
11331 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11332 * actions will be performed on all the elements in this collection.</b>
11334 Roo.CompositeElementLite = function(els){
11335 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11336 this.el = new Roo.Element.Flyweight();
11338 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11339 addElements : function(els){
11341 if(els instanceof Array){
11342 this.elements = this.elements.concat(els);
11344 var yels = this.elements;
11345 var index = yels.length-1;
11346 for(var i = 0, len = els.length; i < len; i++) {
11347 yels[++index] = els[i];
11353 invoke : function(fn, args){
11354 var els = this.elements;
11356 for(var i = 0, len = els.length; i < len; i++) {
11358 Roo.Element.prototype[fn].apply(el, args);
11363 * Returns a flyweight Element of the dom element object at the specified index
11364 * @param {Number} index
11365 * @return {Roo.Element}
11367 item : function(index){
11368 if(!this.elements[index]){
11371 this.el.dom = this.elements[index];
11375 // fixes scope with flyweight
11376 addListener : function(eventName, handler, scope, opt){
11377 var els = this.elements;
11378 for(var i = 0, len = els.length; i < len; i++) {
11379 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11385 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11386 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11387 * a reference to the dom node, use el.dom.</b>
11388 * @param {Function} fn The function to call
11389 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11390 * @return {CompositeElement} this
11392 each : function(fn, scope){
11393 var els = this.elements;
11395 for(var i = 0, len = els.length; i < len; i++){
11397 if(fn.call(scope || el, el, this, i) === false){
11404 indexOf : function(el){
11405 return this.elements.indexOf(Roo.getDom(el));
11408 replaceElement : function(el, replacement, domReplace){
11409 var index = typeof el == 'number' ? el : this.indexOf(el);
11411 replacement = Roo.getDom(replacement);
11413 var d = this.elements[index];
11414 d.parentNode.insertBefore(replacement, d);
11415 d.parentNode.removeChild(d);
11417 this.elements.splice(index, 1, replacement);
11422 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11426 * Ext JS Library 1.1.1
11427 * Copyright(c) 2006-2007, Ext JS, LLC.
11429 * Originally Released Under LGPL - original licence link has changed is not relivant.
11432 * <script type="text/javascript">
11438 * @class Roo.data.Connection
11439 * @extends Roo.util.Observable
11440 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11441 * either to a configured URL, or to a URL specified at request time.<br><br>
11443 * Requests made by this class are asynchronous, and will return immediately. No data from
11444 * the server will be available to the statement immediately following the {@link #request} call.
11445 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11447 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11448 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11449 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11450 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11451 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11452 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11453 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11454 * standard DOM methods.
11456 * @param {Object} config a configuration object.
11458 Roo.data.Connection = function(config){
11459 Roo.apply(this, config);
11462 * @event beforerequest
11463 * Fires before a network request is made to retrieve a data object.
11464 * @param {Connection} conn This Connection object.
11465 * @param {Object} options The options config object passed to the {@link #request} method.
11467 "beforerequest" : true,
11469 * @event requestcomplete
11470 * Fires if the request was successfully completed.
11471 * @param {Connection} conn This Connection object.
11472 * @param {Object} response The XHR object containing the response data.
11473 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11474 * @param {Object} options The options config object passed to the {@link #request} method.
11476 "requestcomplete" : true,
11478 * @event requestexception
11479 * Fires if an error HTTP status was returned from the server.
11480 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11481 * @param {Connection} conn This Connection object.
11482 * @param {Object} response The XHR object containing the response data.
11483 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11484 * @param {Object} options The options config object passed to the {@link #request} method.
11486 "requestexception" : true
11488 Roo.data.Connection.superclass.constructor.call(this);
11491 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11493 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11496 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11497 * extra parameters to each request made by this object. (defaults to undefined)
11500 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11501 * to each request made by this object. (defaults to undefined)
11504 * @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)
11507 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11511 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11517 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11520 disableCaching: true,
11523 * Sends an HTTP request to a remote server.
11524 * @param {Object} options An object which may contain the following properties:<ul>
11525 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11526 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11527 * request, a url encoded string or a function to call to get either.</li>
11528 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11529 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11530 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11531 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11532 * <li>options {Object} The parameter to the request call.</li>
11533 * <li>success {Boolean} True if the request succeeded.</li>
11534 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11536 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11537 * The callback is passed the following parameters:<ul>
11538 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11539 * <li>options {Object} The parameter to the request call.</li>
11541 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11542 * The callback is passed the following parameters:<ul>
11543 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11544 * <li>options {Object} The parameter to the request call.</li>
11546 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11547 * for the callback function. Defaults to the browser window.</li>
11548 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11549 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11550 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11551 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11552 * params for the post data. Any params will be appended to the URL.</li>
11553 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11555 * @return {Number} transactionId
11557 request : function(o){
11558 if(this.fireEvent("beforerequest", this, o) !== false){
11561 if(typeof p == "function"){
11562 p = p.call(o.scope||window, o);
11564 if(typeof p == "object"){
11565 p = Roo.urlEncode(o.params);
11567 if(this.extraParams){
11568 var extras = Roo.urlEncode(this.extraParams);
11569 p = p ? (p + '&' + extras) : extras;
11572 var url = o.url || this.url;
11573 if(typeof url == 'function'){
11574 url = url.call(o.scope||window, o);
11578 var form = Roo.getDom(o.form);
11579 url = url || form.action;
11581 var enctype = form.getAttribute("enctype");
11582 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11583 return this.doFormUpload(o, p, url);
11585 var f = Roo.lib.Ajax.serializeForm(form);
11586 p = p ? (p + '&' + f) : f;
11589 var hs = o.headers;
11590 if(this.defaultHeaders){
11591 hs = Roo.apply(hs || {}, this.defaultHeaders);
11598 success: this.handleResponse,
11599 failure: this.handleFailure,
11601 argument: {options: o},
11602 timeout : o.timeout || this.timeout
11605 var method = o.method||this.method||(p ? "POST" : "GET");
11607 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11608 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11611 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11615 }else if(this.autoAbort !== false){
11619 if((method == 'GET' && p) || o.xmlData){
11620 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11623 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11624 return this.transId;
11626 Roo.callback(o.callback, o.scope, [o, null, null]);
11632 * Determine whether this object has a request outstanding.
11633 * @param {Number} transactionId (Optional) defaults to the last transaction
11634 * @return {Boolean} True if there is an outstanding request.
11636 isLoading : function(transId){
11638 return Roo.lib.Ajax.isCallInProgress(transId);
11640 return this.transId ? true : false;
11645 * Aborts any outstanding request.
11646 * @param {Number} transactionId (Optional) defaults to the last transaction
11648 abort : function(transId){
11649 if(transId || this.isLoading()){
11650 Roo.lib.Ajax.abort(transId || this.transId);
11655 handleResponse : function(response){
11656 this.transId = false;
11657 var options = response.argument.options;
11658 response.argument = options ? options.argument : null;
11659 this.fireEvent("requestcomplete", this, response, options);
11660 Roo.callback(options.success, options.scope, [response, options]);
11661 Roo.callback(options.callback, options.scope, [options, true, response]);
11665 handleFailure : function(response, e){
11666 this.transId = false;
11667 var options = response.argument.options;
11668 response.argument = options ? options.argument : null;
11669 this.fireEvent("requestexception", this, response, options, e);
11670 Roo.callback(options.failure, options.scope, [response, options]);
11671 Roo.callback(options.callback, options.scope, [options, false, response]);
11675 doFormUpload : function(o, ps, url){
11677 var frame = document.createElement('iframe');
11680 frame.className = 'x-hidden';
11682 frame.src = Roo.SSL_SECURE_URL;
11684 document.body.appendChild(frame);
11687 document.frames[id].name = id;
11690 var form = Roo.getDom(o.form);
11692 form.method = 'POST';
11693 form.enctype = form.encoding = 'multipart/form-data';
11699 if(ps){ // add dynamic params
11701 ps = Roo.urlDecode(ps, false);
11703 if(ps.hasOwnProperty(k)){
11704 hd = document.createElement('input');
11705 hd.type = 'hidden';
11708 form.appendChild(hd);
11715 var r = { // bogus response object
11720 r.argument = o ? o.argument : null;
11725 doc = frame.contentWindow.document;
11727 doc = (frame.contentDocument || window.frames[id].document);
11729 if(doc && doc.body){
11730 r.responseText = doc.body.innerHTML;
11732 if(doc && doc.XMLDocument){
11733 r.responseXML = doc.XMLDocument;
11735 r.responseXML = doc;
11742 Roo.EventManager.removeListener(frame, 'load', cb, this);
11744 this.fireEvent("requestcomplete", this, r, o);
11745 Roo.callback(o.success, o.scope, [r, o]);
11746 Roo.callback(o.callback, o.scope, [o, true, r]);
11748 setTimeout(function(){document.body.removeChild(frame);}, 100);
11751 Roo.EventManager.on(frame, 'load', cb, this);
11754 if(hiddens){ // remove dynamic params
11755 for(var i = 0, len = hiddens.length; i < len; i++){
11756 form.removeChild(hiddens[i]);
11763 * Ext JS Library 1.1.1
11764 * Copyright(c) 2006-2007, Ext JS, LLC.
11766 * Originally Released Under LGPL - original licence link has changed is not relivant.
11769 * <script type="text/javascript">
11773 * Global Ajax request class.
11776 * @extends Roo.data.Connection
11779 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11780 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11781 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11782 * @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)
11783 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11784 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11785 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11787 Roo.Ajax = new Roo.data.Connection({
11796 * Serialize the passed form into a url encoded string
11798 * @param {String/HTMLElement} form
11801 serializeForm : function(form){
11802 return Roo.lib.Ajax.serializeForm(form);
11806 * Ext JS Library 1.1.1
11807 * Copyright(c) 2006-2007, Ext JS, LLC.
11809 * Originally Released Under LGPL - original licence link has changed is not relivant.
11812 * <script type="text/javascript">
11817 * @class Roo.UpdateManager
11818 * @extends Roo.util.Observable
11819 * Provides AJAX-style update for Element object.<br><br>
11822 * // Get it from a Roo.Element object
11823 * var el = Roo.get("foo");
11824 * var mgr = el.getUpdateManager();
11825 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11827 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11829 * // or directly (returns the same UpdateManager instance)
11830 * var mgr = new Roo.UpdateManager("myElementId");
11831 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11832 * mgr.on("update", myFcnNeedsToKnow);
11834 // short handed call directly from the element object
11835 Roo.get("foo").load({
11839 text: "Loading Foo..."
11843 * Create new UpdateManager directly.
11844 * @param {String/HTMLElement/Roo.Element} el The element to update
11845 * @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).
11847 Roo.UpdateManager = function(el, forceNew){
11849 if(!forceNew && el.updateManager){
11850 return el.updateManager;
11853 * The Element object
11854 * @type Roo.Element
11858 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11861 this.defaultUrl = null;
11865 * @event beforeupdate
11866 * Fired before an update is made, return false from your handler and the update is cancelled.
11867 * @param {Roo.Element} el
11868 * @param {String/Object/Function} url
11869 * @param {String/Object} params
11871 "beforeupdate": true,
11874 * Fired after successful update is made.
11875 * @param {Roo.Element} el
11876 * @param {Object} oResponseObject The response Object
11881 * Fired on update failure.
11882 * @param {Roo.Element} el
11883 * @param {Object} oResponseObject The response Object
11887 var d = Roo.UpdateManager.defaults;
11889 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11892 this.sslBlankUrl = d.sslBlankUrl;
11894 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11897 this.disableCaching = d.disableCaching;
11899 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11902 this.indicatorText = d.indicatorText;
11904 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11907 this.showLoadIndicator = d.showLoadIndicator;
11909 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11912 this.timeout = d.timeout;
11915 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11918 this.loadScripts = d.loadScripts;
11921 * Transaction object of current executing transaction
11923 this.transaction = null;
11928 this.autoRefreshProcId = null;
11930 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11933 this.refreshDelegate = this.refresh.createDelegate(this);
11935 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11938 this.updateDelegate = this.update.createDelegate(this);
11940 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11943 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11947 this.successDelegate = this.processSuccess.createDelegate(this);
11951 this.failureDelegate = this.processFailure.createDelegate(this);
11953 if(!this.renderer){
11955 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11957 this.renderer = new Roo.UpdateManager.BasicRenderer();
11960 Roo.UpdateManager.superclass.constructor.call(this);
11963 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11965 * Get the Element this UpdateManager is bound to
11966 * @return {Roo.Element} The element
11968 getEl : function(){
11972 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11973 * @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:
11976 url: "your-url.php",<br/>
11977 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11978 callback: yourFunction,<br/>
11979 scope: yourObject, //(optional scope) <br/>
11980 discardUrl: false, <br/>
11981 nocache: false,<br/>
11982 text: "Loading...",<br/>
11984 scripts: false<br/>
11987 * The only required property is url. The optional properties nocache, text and scripts
11988 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11989 * @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}
11990 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11991 * @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.
11993 update : function(url, params, callback, discardUrl){
11994 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11995 var method = this.method,
11997 if(typeof url == "object"){ // must be config object
12000 params = params || cfg.params;
12001 callback = callback || cfg.callback;
12002 discardUrl = discardUrl || cfg.discardUrl;
12003 if(callback && cfg.scope){
12004 callback = callback.createDelegate(cfg.scope);
12006 if(typeof cfg.method != "undefined"){method = cfg.method;};
12007 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12008 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12009 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12010 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12012 this.showLoading();
12014 this.defaultUrl = url;
12016 if(typeof url == "function"){
12017 url = url.call(this);
12020 method = method || (params ? "POST" : "GET");
12021 if(method == "GET"){
12022 url = this.prepareUrl(url);
12025 var o = Roo.apply(cfg ||{}, {
12028 success: this.successDelegate,
12029 failure: this.failureDelegate,
12030 callback: undefined,
12031 timeout: (this.timeout*1000),
12032 argument: {"url": url, "form": null, "callback": callback, "params": params}
12034 Roo.log("updated manager called with timeout of " + o.timeout);
12035 this.transaction = Roo.Ajax.request(o);
12040 * 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.
12041 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12042 * @param {String/HTMLElement} form The form Id or form element
12043 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12044 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12045 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12047 formUpdate : function(form, url, reset, callback){
12048 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12049 if(typeof url == "function"){
12050 url = url.call(this);
12052 form = Roo.getDom(form);
12053 this.transaction = Roo.Ajax.request({
12056 success: this.successDelegate,
12057 failure: this.failureDelegate,
12058 timeout: (this.timeout*1000),
12059 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12061 this.showLoading.defer(1, this);
12066 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12067 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12069 refresh : function(callback){
12070 if(this.defaultUrl == null){
12073 this.update(this.defaultUrl, null, callback, true);
12077 * Set this element to auto refresh.
12078 * @param {Number} interval How often to update (in seconds).
12079 * @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)
12080 * @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}
12081 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12082 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12084 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12086 this.update(url || this.defaultUrl, params, callback, true);
12088 if(this.autoRefreshProcId){
12089 clearInterval(this.autoRefreshProcId);
12091 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12095 * Stop auto refresh on this element.
12097 stopAutoRefresh : function(){
12098 if(this.autoRefreshProcId){
12099 clearInterval(this.autoRefreshProcId);
12100 delete this.autoRefreshProcId;
12104 isAutoRefreshing : function(){
12105 return this.autoRefreshProcId ? true : false;
12108 * Called to update the element to "Loading" state. Override to perform custom action.
12110 showLoading : function(){
12111 if(this.showLoadIndicator){
12112 this.el.update(this.indicatorText);
12117 * Adds unique parameter to query string if disableCaching = true
12120 prepareUrl : function(url){
12121 if(this.disableCaching){
12122 var append = "_dc=" + (new Date().getTime());
12123 if(url.indexOf("?") !== -1){
12124 url += "&" + append;
12126 url += "?" + append;
12135 processSuccess : function(response){
12136 this.transaction = null;
12137 if(response.argument.form && response.argument.reset){
12138 try{ // put in try/catch since some older FF releases had problems with this
12139 response.argument.form.reset();
12142 if(this.loadScripts){
12143 this.renderer.render(this.el, response, this,
12144 this.updateComplete.createDelegate(this, [response]));
12146 this.renderer.render(this.el, response, this);
12147 this.updateComplete(response);
12151 updateComplete : function(response){
12152 this.fireEvent("update", this.el, response);
12153 if(typeof response.argument.callback == "function"){
12154 response.argument.callback(this.el, true, response);
12161 processFailure : function(response){
12162 this.transaction = null;
12163 this.fireEvent("failure", this.el, response);
12164 if(typeof response.argument.callback == "function"){
12165 response.argument.callback(this.el, false, response);
12170 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12171 * @param {Object} renderer The object implementing the render() method
12173 setRenderer : function(renderer){
12174 this.renderer = renderer;
12177 getRenderer : function(){
12178 return this.renderer;
12182 * Set the defaultUrl used for updates
12183 * @param {String/Function} defaultUrl The url or a function to call to get the url
12185 setDefaultUrl : function(defaultUrl){
12186 this.defaultUrl = defaultUrl;
12190 * Aborts the executing transaction
12192 abort : function(){
12193 if(this.transaction){
12194 Roo.Ajax.abort(this.transaction);
12199 * Returns true if an update is in progress
12200 * @return {Boolean}
12202 isUpdating : function(){
12203 if(this.transaction){
12204 return Roo.Ajax.isLoading(this.transaction);
12211 * @class Roo.UpdateManager.defaults
12212 * @static (not really - but it helps the doc tool)
12213 * The defaults collection enables customizing the default properties of UpdateManager
12215 Roo.UpdateManager.defaults = {
12217 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12223 * True to process scripts by default (Defaults to false).
12226 loadScripts : false,
12229 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12232 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12234 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12237 disableCaching : false,
12239 * Whether to show indicatorText when loading (Defaults to true).
12242 showLoadIndicator : true,
12244 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12247 indicatorText : '<div class="loading-indicator">Loading...</div>'
12251 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12253 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12254 * @param {String/HTMLElement/Roo.Element} el The element to update
12255 * @param {String} url The url
12256 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12257 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12260 * @member Roo.UpdateManager
12262 Roo.UpdateManager.updateElement = function(el, url, params, options){
12263 var um = Roo.get(el, true).getUpdateManager();
12264 Roo.apply(um, options);
12265 um.update(url, params, options ? options.callback : null);
12267 // alias for backwards compat
12268 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12270 * @class Roo.UpdateManager.BasicRenderer
12271 * Default Content renderer. Updates the elements innerHTML with the responseText.
12273 Roo.UpdateManager.BasicRenderer = function(){};
12275 Roo.UpdateManager.BasicRenderer.prototype = {
12277 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12278 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12279 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12280 * @param {Roo.Element} el The element being rendered
12281 * @param {Object} response The YUI Connect response object
12282 * @param {UpdateManager} updateManager The calling update manager
12283 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12285 render : function(el, response, updateManager, callback){
12286 el.update(response.responseText, updateManager.loadScripts, callback);
12292 * (c)) Alan Knowles
12298 * @class Roo.DomTemplate
12299 * @extends Roo.Template
12300 * An effort at a dom based template engine..
12302 * Similar to XTemplate, except it uses dom parsing to create the template..
12304 * Supported features:
12309 {a_variable} - output encoded.
12310 {a_variable.format:("Y-m-d")} - call a method on the variable
12311 {a_variable:raw} - unencoded output
12312 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12313 {a_variable:this.method_on_template(...)} - call a method on the template object.
12318 <div roo-for="a_variable or condition.."></div>
12319 <div roo-if="a_variable or condition"></div>
12320 <div roo-exec="some javascript"></div>
12321 <div roo-name="named_template"></div>
12326 Roo.DomTemplate = function()
12328 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12335 Roo.extend(Roo.DomTemplate, Roo.Template, {
12337 * id counter for sub templates.
12341 * flag to indicate if dom parser is inside a pre,
12342 * it will strip whitespace if not.
12347 * The various sub templates
12355 * basic tag replacing syntax
12358 * // you can fake an object call by doing this
12362 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12363 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12365 iterChild : function (node, method) {
12367 var oldPre = this.inPre;
12368 if (node.tagName == 'PRE') {
12371 for( var i = 0; i < node.childNodes.length; i++) {
12372 method.call(this, node.childNodes[i]);
12374 this.inPre = oldPre;
12380 * compile the template
12382 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12385 compile: function()
12389 // covert the html into DOM...
12393 doc = document.implementation.createHTMLDocument("");
12394 doc.documentElement.innerHTML = this.html ;
12395 div = doc.documentElement;
12397 // old IE... - nasty -- it causes all sorts of issues.. with
12398 // images getting pulled from server..
12399 div = document.createElement('div');
12400 div.innerHTML = this.html;
12402 //doc.documentElement.innerHTML = htmlBody
12408 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12410 var tpls = this.tpls;
12412 // create a top level template from the snippet..
12414 //Roo.log(div.innerHTML);
12421 body : div.innerHTML,
12434 Roo.each(tpls, function(tp){
12435 this.compileTpl(tp);
12436 this.tpls[tp.id] = tp;
12439 this.master = tpls[0];
12445 compileNode : function(node, istop) {
12450 // skip anything not a tag..
12451 if (node.nodeType != 1) {
12452 if (node.nodeType == 3 && !this.inPre) {
12453 // reduce white space..
12454 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12477 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12478 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12479 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12480 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12486 // just itterate children..
12487 this.iterChild(node,this.compileNode);
12490 tpl.uid = this.id++;
12491 tpl.value = node.getAttribute('roo-' + tpl.attr);
12492 node.removeAttribute('roo-'+ tpl.attr);
12493 if (tpl.attr != 'name') {
12494 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12495 node.parentNode.replaceChild(placeholder, node);
12498 var placeholder = document.createElement('span');
12499 placeholder.className = 'roo-tpl-' + tpl.value;
12500 node.parentNode.replaceChild(placeholder, node);
12503 // parent now sees '{domtplXXXX}
12504 this.iterChild(node,this.compileNode);
12506 // we should now have node body...
12507 var div = document.createElement('div');
12508 div.appendChild(node);
12510 // this has the unfortunate side effect of converting tagged attributes
12511 // eg. href="{...}" into %7C...%7D
12512 // this has been fixed by searching for those combo's although it's a bit hacky..
12515 tpl.body = div.innerHTML;
12522 switch (tpl.value) {
12523 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12524 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12525 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12530 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12534 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12538 tpl.id = tpl.value; // replace non characters???
12544 this.tpls.push(tpl);
12554 * Compile a segment of the template into a 'sub-template'
12560 compileTpl : function(tpl)
12562 var fm = Roo.util.Format;
12563 var useF = this.disableFormats !== true;
12565 var sep = Roo.isGecko ? "+\n" : ",\n";
12567 var undef = function(str) {
12568 Roo.debug && Roo.log("Property not found :" + str);
12572 //Roo.log(tpl.body);
12576 var fn = function(m, lbrace, name, format, args)
12579 //Roo.log(arguments);
12580 args = args ? args.replace(/\\'/g,"'") : args;
12581 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12582 if (typeof(format) == 'undefined') {
12583 format = 'htmlEncode';
12585 if (format == 'raw' ) {
12589 if(name.substr(0, 6) == 'domtpl'){
12590 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12593 // build an array of options to determine if value is undefined..
12595 // basically get 'xxxx.yyyy' then do
12596 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12597 // (function () { Roo.log("Property not found"); return ''; })() :
12602 Roo.each(name.split('.'), function(st) {
12603 lookfor += (lookfor.length ? '.': '') + st;
12604 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12607 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12610 if(format && useF){
12612 args = args ? ',' + args : "";
12614 if(format.substr(0, 5) != "this."){
12615 format = "fm." + format + '(';
12617 format = 'this.call("'+ format.substr(5) + '", ';
12621 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12624 if (args && args.length) {
12625 // called with xxyx.yuu:(test,test)
12627 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12629 // raw.. - :raw modifier..
12630 return "'"+ sep + udef_st + name + ")"+sep+"'";
12634 // branched to use + in gecko and [].join() in others
12636 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12637 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12640 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12641 body.push(tpl.body.replace(/(\r\n|\n)/g,
12642 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12643 body.push("'].join('');};};");
12644 body = body.join('');
12647 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12649 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12656 * same as applyTemplate, except it's done to one of the subTemplates
12657 * when using named templates, you can do:
12659 * var str = pl.applySubTemplate('your-name', values);
12662 * @param {Number} id of the template
12663 * @param {Object} values to apply to template
12664 * @param {Object} parent (normaly the instance of this object)
12666 applySubTemplate : function(id, values, parent)
12670 var t = this.tpls[id];
12674 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12675 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12679 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12686 if(t.execCall && t.execCall.call(this, values, parent)){
12690 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12696 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12697 parent = t.target ? values : parent;
12698 if(t.forCall && vs instanceof Array){
12700 for(var i = 0, len = vs.length; i < len; i++){
12702 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12704 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12706 //Roo.log(t.compiled);
12710 return buf.join('');
12713 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12718 return t.compiled.call(this, vs, parent);
12720 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12722 //Roo.log(t.compiled);
12730 applyTemplate : function(values){
12731 return this.master.compiled.call(this, values, {});
12732 //var s = this.subs;
12735 apply : function(){
12736 return this.applyTemplate.apply(this, arguments);
12741 Roo.DomTemplate.from = function(el){
12742 el = Roo.getDom(el);
12743 return new Roo.Domtemplate(el.value || el.innerHTML);
12746 * Ext JS Library 1.1.1
12747 * Copyright(c) 2006-2007, Ext JS, LLC.
12749 * Originally Released Under LGPL - original licence link has changed is not relivant.
12752 * <script type="text/javascript">
12756 * @class Roo.util.DelayedTask
12757 * Provides a convenient method of performing setTimeout where a new
12758 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12759 * You can use this class to buffer
12760 * the keypress events for a certain number of milliseconds, and perform only if they stop
12761 * for that amount of time.
12762 * @constructor The parameters to this constructor serve as defaults and are not required.
12763 * @param {Function} fn (optional) The default function to timeout
12764 * @param {Object} scope (optional) The default scope of that timeout
12765 * @param {Array} args (optional) The default Array of arguments
12767 Roo.util.DelayedTask = function(fn, scope, args){
12768 var id = null, d, t;
12770 var call = function(){
12771 var now = new Date().getTime();
12775 fn.apply(scope, args || []);
12779 * Cancels any pending timeout and queues a new one
12780 * @param {Number} delay The milliseconds to delay
12781 * @param {Function} newFn (optional) Overrides function passed to constructor
12782 * @param {Object} newScope (optional) Overrides scope passed to constructor
12783 * @param {Array} newArgs (optional) Overrides args passed to constructor
12785 this.delay = function(delay, newFn, newScope, newArgs){
12786 if(id && delay != d){
12790 t = new Date().getTime();
12792 scope = newScope || scope;
12793 args = newArgs || args;
12795 id = setInterval(call, d);
12800 * Cancel the last queued timeout
12802 this.cancel = function(){
12810 * Ext JS Library 1.1.1
12811 * Copyright(c) 2006-2007, Ext JS, LLC.
12813 * Originally Released Under LGPL - original licence link has changed is not relivant.
12816 * <script type="text/javascript">
12820 Roo.util.TaskRunner = function(interval){
12821 interval = interval || 10;
12822 var tasks = [], removeQueue = [];
12824 var running = false;
12826 var stopThread = function(){
12832 var startThread = function(){
12835 id = setInterval(runTasks, interval);
12839 var removeTask = function(task){
12840 removeQueue.push(task);
12846 var runTasks = function(){
12847 if(removeQueue.length > 0){
12848 for(var i = 0, len = removeQueue.length; i < len; i++){
12849 tasks.remove(removeQueue[i]);
12852 if(tasks.length < 1){
12857 var now = new Date().getTime();
12858 for(var i = 0, len = tasks.length; i < len; ++i){
12860 var itime = now - t.taskRunTime;
12861 if(t.interval <= itime){
12862 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12863 t.taskRunTime = now;
12864 if(rt === false || t.taskRunCount === t.repeat){
12869 if(t.duration && t.duration <= (now - t.taskStartTime)){
12876 * Queues a new task.
12877 * @param {Object} task
12879 this.start = function(task){
12881 task.taskStartTime = new Date().getTime();
12882 task.taskRunTime = 0;
12883 task.taskRunCount = 0;
12888 this.stop = function(task){
12893 this.stopAll = function(){
12895 for(var i = 0, len = tasks.length; i < len; i++){
12896 if(tasks[i].onStop){
12905 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12907 * Ext JS Library 1.1.1
12908 * Copyright(c) 2006-2007, Ext JS, LLC.
12910 * Originally Released Under LGPL - original licence link has changed is not relivant.
12913 * <script type="text/javascript">
12918 * @class Roo.util.MixedCollection
12919 * @extends Roo.util.Observable
12920 * A Collection class that maintains both numeric indexes and keys and exposes events.
12922 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12923 * collection (defaults to false)
12924 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12925 * and return the key value for that item. This is used when available to look up the key on items that
12926 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12927 * equivalent to providing an implementation for the {@link #getKey} method.
12929 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12937 * Fires when the collection is cleared.
12942 * Fires when an item is added to the collection.
12943 * @param {Number} index The index at which the item was added.
12944 * @param {Object} o The item added.
12945 * @param {String} key The key associated with the added item.
12950 * Fires when an item is replaced in the collection.
12951 * @param {String} key he key associated with the new added.
12952 * @param {Object} old The item being replaced.
12953 * @param {Object} new The new item.
12958 * Fires when an item is removed from the collection.
12959 * @param {Object} o The item being removed.
12960 * @param {String} key (optional) The key associated with the removed item.
12965 this.allowFunctions = allowFunctions === true;
12967 this.getKey = keyFn;
12969 Roo.util.MixedCollection.superclass.constructor.call(this);
12972 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12973 allowFunctions : false,
12976 * Adds an item to the collection.
12977 * @param {String} key The key to associate with the item
12978 * @param {Object} o The item to add.
12979 * @return {Object} The item added.
12981 add : function(key, o){
12982 if(arguments.length == 1){
12984 key = this.getKey(o);
12986 if(typeof key == "undefined" || key === null){
12988 this.items.push(o);
12989 this.keys.push(null);
12991 var old = this.map[key];
12993 return this.replace(key, o);
12996 this.items.push(o);
12998 this.keys.push(key);
13000 this.fireEvent("add", this.length-1, o, key);
13005 * MixedCollection has a generic way to fetch keys if you implement getKey.
13008 var mc = new Roo.util.MixedCollection();
13009 mc.add(someEl.dom.id, someEl);
13010 mc.add(otherEl.dom.id, otherEl);
13014 var mc = new Roo.util.MixedCollection();
13015 mc.getKey = function(el){
13021 // or via the constructor
13022 var mc = new Roo.util.MixedCollection(false, function(el){
13028 * @param o {Object} The item for which to find the key.
13029 * @return {Object} The key for the passed item.
13031 getKey : function(o){
13036 * Replaces an item in the collection.
13037 * @param {String} key The key associated with the item to replace, or the item to replace.
13038 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13039 * @return {Object} The new item.
13041 replace : function(key, o){
13042 if(arguments.length == 1){
13044 key = this.getKey(o);
13046 var old = this.item(key);
13047 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13048 return this.add(key, o);
13050 var index = this.indexOfKey(key);
13051 this.items[index] = o;
13053 this.fireEvent("replace", key, old, o);
13058 * Adds all elements of an Array or an Object to the collection.
13059 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13060 * an Array of values, each of which are added to the collection.
13062 addAll : function(objs){
13063 if(arguments.length > 1 || objs instanceof Array){
13064 var args = arguments.length > 1 ? arguments : objs;
13065 for(var i = 0, len = args.length; i < len; i++){
13069 for(var key in objs){
13070 if(this.allowFunctions || typeof objs[key] != "function"){
13071 this.add(key, objs[key]);
13078 * Executes the specified function once for every item in the collection, passing each
13079 * item as the first and only parameter. returning false from the function will stop the iteration.
13080 * @param {Function} fn The function to execute for each item.
13081 * @param {Object} scope (optional) The scope in which to execute the function.
13083 each : function(fn, scope){
13084 var items = [].concat(this.items); // each safe for removal
13085 for(var i = 0, len = items.length; i < len; i++){
13086 if(fn.call(scope || items[i], items[i], i, len) === false){
13093 * Executes the specified function once for every key in the collection, passing each
13094 * key, and its associated item as the first two parameters.
13095 * @param {Function} fn The function to execute for each item.
13096 * @param {Object} scope (optional) The scope in which to execute the function.
13098 eachKey : function(fn, scope){
13099 for(var i = 0, len = this.keys.length; i < len; i++){
13100 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13105 * Returns the first item in the collection which elicits a true return value from the
13106 * passed selection function.
13107 * @param {Function} fn The selection function to execute for each item.
13108 * @param {Object} scope (optional) The scope in which to execute the function.
13109 * @return {Object} The first item in the collection which returned true from the selection function.
13111 find : function(fn, scope){
13112 for(var i = 0, len = this.items.length; i < len; i++){
13113 if(fn.call(scope || window, this.items[i], this.keys[i])){
13114 return this.items[i];
13121 * Inserts an item at the specified index in the collection.
13122 * @param {Number} index The index to insert the item at.
13123 * @param {String} key The key to associate with the new item, or the item itself.
13124 * @param {Object} o (optional) If the second parameter was a key, the new item.
13125 * @return {Object} The item inserted.
13127 insert : function(index, key, o){
13128 if(arguments.length == 2){
13130 key = this.getKey(o);
13132 if(index >= this.length){
13133 return this.add(key, o);
13136 this.items.splice(index, 0, o);
13137 if(typeof key != "undefined" && key != null){
13140 this.keys.splice(index, 0, key);
13141 this.fireEvent("add", index, o, key);
13146 * Removed an item from the collection.
13147 * @param {Object} o The item to remove.
13148 * @return {Object} The item removed.
13150 remove : function(o){
13151 return this.removeAt(this.indexOf(o));
13155 * Remove an item from a specified index in the collection.
13156 * @param {Number} index The index within the collection of the item to remove.
13158 removeAt : function(index){
13159 if(index < this.length && index >= 0){
13161 var o = this.items[index];
13162 this.items.splice(index, 1);
13163 var key = this.keys[index];
13164 if(typeof key != "undefined"){
13165 delete this.map[key];
13167 this.keys.splice(index, 1);
13168 this.fireEvent("remove", o, key);
13173 * Removed an item associated with the passed key fom the collection.
13174 * @param {String} key The key of the item to remove.
13176 removeKey : function(key){
13177 return this.removeAt(this.indexOfKey(key));
13181 * Returns the number of items in the collection.
13182 * @return {Number} the number of items in the collection.
13184 getCount : function(){
13185 return this.length;
13189 * Returns index within the collection of the passed Object.
13190 * @param {Object} o The item to find the index of.
13191 * @return {Number} index of the item.
13193 indexOf : function(o){
13194 if(!this.items.indexOf){
13195 for(var i = 0, len = this.items.length; i < len; i++){
13196 if(this.items[i] == o) {
13202 return this.items.indexOf(o);
13207 * Returns index within the collection of the passed key.
13208 * @param {String} key The key to find the index of.
13209 * @return {Number} index of the key.
13211 indexOfKey : function(key){
13212 if(!this.keys.indexOf){
13213 for(var i = 0, len = this.keys.length; i < len; i++){
13214 if(this.keys[i] == key) {
13220 return this.keys.indexOf(key);
13225 * Returns the item associated with the passed key OR index. Key has priority over index.
13226 * @param {String/Number} key The key or index of the item.
13227 * @return {Object} The item associated with the passed key.
13229 item : function(key){
13230 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13231 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13235 * Returns the item at the specified index.
13236 * @param {Number} index The index of the item.
13239 itemAt : function(index){
13240 return this.items[index];
13244 * Returns the item associated with the passed key.
13245 * @param {String/Number} key The key of the item.
13246 * @return {Object} The item associated with the passed key.
13248 key : function(key){
13249 return this.map[key];
13253 * Returns true if the collection contains the passed Object as an item.
13254 * @param {Object} o The Object to look for in the collection.
13255 * @return {Boolean} True if the collection contains the Object as an item.
13257 contains : function(o){
13258 return this.indexOf(o) != -1;
13262 * Returns true if the collection contains the passed Object as a key.
13263 * @param {String} key The key to look for in the collection.
13264 * @return {Boolean} True if the collection contains the Object as a key.
13266 containsKey : function(key){
13267 return typeof this.map[key] != "undefined";
13271 * Removes all items from the collection.
13273 clear : function(){
13278 this.fireEvent("clear");
13282 * Returns the first item in the collection.
13283 * @return {Object} the first item in the collection..
13285 first : function(){
13286 return this.items[0];
13290 * Returns the last item in the collection.
13291 * @return {Object} the last item in the collection..
13294 return this.items[this.length-1];
13297 _sort : function(property, dir, fn){
13298 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13299 fn = fn || function(a, b){
13302 var c = [], k = this.keys, items = this.items;
13303 for(var i = 0, len = items.length; i < len; i++){
13304 c[c.length] = {key: k[i], value: items[i], index: i};
13306 c.sort(function(a, b){
13307 var v = fn(a[property], b[property]) * dsc;
13309 v = (a.index < b.index ? -1 : 1);
13313 for(var i = 0, len = c.length; i < len; i++){
13314 items[i] = c[i].value;
13317 this.fireEvent("sort", this);
13321 * Sorts this collection with the passed comparison function
13322 * @param {String} direction (optional) "ASC" or "DESC"
13323 * @param {Function} fn (optional) comparison function
13325 sort : function(dir, fn){
13326 this._sort("value", dir, fn);
13330 * Sorts this collection by keys
13331 * @param {String} direction (optional) "ASC" or "DESC"
13332 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13334 keySort : function(dir, fn){
13335 this._sort("key", dir, fn || function(a, b){
13336 return String(a).toUpperCase()-String(b).toUpperCase();
13341 * Returns a range of items in this collection
13342 * @param {Number} startIndex (optional) defaults to 0
13343 * @param {Number} endIndex (optional) default to the last item
13344 * @return {Array} An array of items
13346 getRange : function(start, end){
13347 var items = this.items;
13348 if(items.length < 1){
13351 start = start || 0;
13352 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13355 for(var i = start; i <= end; i++) {
13356 r[r.length] = items[i];
13359 for(var i = start; i >= end; i--) {
13360 r[r.length] = items[i];
13367 * Filter the <i>objects</i> in this collection by a specific property.
13368 * Returns a new collection that has been filtered.
13369 * @param {String} property A property on your objects
13370 * @param {String/RegExp} value Either string that the property values
13371 * should start with or a RegExp to test against the property
13372 * @return {MixedCollection} The new filtered collection
13374 filter : function(property, value){
13375 if(!value.exec){ // not a regex
13376 value = String(value);
13377 if(value.length == 0){
13378 return this.clone();
13380 value = new RegExp("^" + Roo.escapeRe(value), "i");
13382 return this.filterBy(function(o){
13383 return o && value.test(o[property]);
13388 * Filter by a function. * Returns a new collection that has been filtered.
13389 * The passed function will be called with each
13390 * object in the collection. If the function returns true, the value is included
13391 * otherwise it is filtered.
13392 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13393 * @param {Object} scope (optional) The scope of the function (defaults to this)
13394 * @return {MixedCollection} The new filtered collection
13396 filterBy : function(fn, scope){
13397 var r = new Roo.util.MixedCollection();
13398 r.getKey = this.getKey;
13399 var k = this.keys, it = this.items;
13400 for(var i = 0, len = it.length; i < len; i++){
13401 if(fn.call(scope||this, it[i], k[i])){
13402 r.add(k[i], it[i]);
13409 * Creates a duplicate of this collection
13410 * @return {MixedCollection}
13412 clone : function(){
13413 var r = new Roo.util.MixedCollection();
13414 var k = this.keys, it = this.items;
13415 for(var i = 0, len = it.length; i < len; i++){
13416 r.add(k[i], it[i]);
13418 r.getKey = this.getKey;
13423 * Returns the item associated with the passed key or index.
13425 * @param {String/Number} key The key or index of the item.
13426 * @return {Object} The item associated with the passed key.
13428 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13430 * Ext JS Library 1.1.1
13431 * Copyright(c) 2006-2007, Ext JS, LLC.
13433 * Originally Released Under LGPL - original licence link has changed is not relivant.
13436 * <script type="text/javascript">
13439 * @class Roo.util.JSON
13440 * Modified version of Douglas Crockford"s json.js that doesn"t
13441 * mess with the Object prototype
13442 * http://www.json.org/js.html
13445 Roo.util.JSON = new (function(){
13446 var useHasOwn = {}.hasOwnProperty ? true : false;
13448 // crashes Safari in some instances
13449 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13451 var pad = function(n) {
13452 return n < 10 ? "0" + n : n;
13465 var encodeString = function(s){
13466 if (/["\\\x00-\x1f]/.test(s)) {
13467 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13472 c = b.charCodeAt();
13474 Math.floor(c / 16).toString(16) +
13475 (c % 16).toString(16);
13478 return '"' + s + '"';
13481 var encodeArray = function(o){
13482 var a = ["["], b, i, l = o.length, v;
13483 for (i = 0; i < l; i += 1) {
13485 switch (typeof v) {
13494 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13502 var encodeDate = function(o){
13503 return '"' + o.getFullYear() + "-" +
13504 pad(o.getMonth() + 1) + "-" +
13505 pad(o.getDate()) + "T" +
13506 pad(o.getHours()) + ":" +
13507 pad(o.getMinutes()) + ":" +
13508 pad(o.getSeconds()) + '"';
13512 * Encodes an Object, Array or other value
13513 * @param {Mixed} o The variable to encode
13514 * @return {String} The JSON string
13516 this.encode = function(o)
13518 // should this be extended to fully wrap stringify..
13520 if(typeof o == "undefined" || o === null){
13522 }else if(o instanceof Array){
13523 return encodeArray(o);
13524 }else if(o instanceof Date){
13525 return encodeDate(o);
13526 }else if(typeof o == "string"){
13527 return encodeString(o);
13528 }else if(typeof o == "number"){
13529 return isFinite(o) ? String(o) : "null";
13530 }else if(typeof o == "boolean"){
13533 var a = ["{"], b, i, v;
13535 if(!useHasOwn || o.hasOwnProperty(i)) {
13537 switch (typeof v) {
13546 a.push(this.encode(i), ":",
13547 v === null ? "null" : this.encode(v));
13558 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13559 * @param {String} json The JSON string
13560 * @return {Object} The resulting object
13562 this.decode = function(json){
13564 return /** eval:var:json */ eval("(" + json + ')');
13568 * Shorthand for {@link Roo.util.JSON#encode}
13569 * @member Roo encode
13571 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13573 * Shorthand for {@link Roo.util.JSON#decode}
13574 * @member Roo decode
13576 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13579 * Ext JS Library 1.1.1
13580 * Copyright(c) 2006-2007, Ext JS, LLC.
13582 * Originally Released Under LGPL - original licence link has changed is not relivant.
13585 * <script type="text/javascript">
13589 * @class Roo.util.Format
13590 * Reusable data formatting functions
13593 Roo.util.Format = function(){
13594 var trimRe = /^\s+|\s+$/g;
13597 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13598 * @param {String} value The string to truncate
13599 * @param {Number} length The maximum length to allow before truncating
13600 * @return {String} The converted text
13602 ellipsis : function(value, len){
13603 if(value && value.length > len){
13604 return value.substr(0, len-3)+"...";
13610 * Checks a reference and converts it to empty string if it is undefined
13611 * @param {Mixed} value Reference to check
13612 * @return {Mixed} Empty string if converted, otherwise the original value
13614 undef : function(value){
13615 return typeof value != "undefined" ? value : "";
13619 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13620 * @param {String} value The string to encode
13621 * @return {String} The encoded text
13623 htmlEncode : function(value){
13624 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13628 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13629 * @param {String} value The string to decode
13630 * @return {String} The decoded text
13632 htmlDecode : function(value){
13633 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13637 * Trims any whitespace from either side of a string
13638 * @param {String} value The text to trim
13639 * @return {String} The trimmed text
13641 trim : function(value){
13642 return String(value).replace(trimRe, "");
13646 * Returns a substring from within an original string
13647 * @param {String} value The original text
13648 * @param {Number} start The start index of the substring
13649 * @param {Number} length The length of the substring
13650 * @return {String} The substring
13652 substr : function(value, start, length){
13653 return String(value).substr(start, length);
13657 * Converts a string to all lower case letters
13658 * @param {String} value The text to convert
13659 * @return {String} The converted text
13661 lowercase : function(value){
13662 return String(value).toLowerCase();
13666 * Converts a string to all upper case letters
13667 * @param {String} value The text to convert
13668 * @return {String} The converted text
13670 uppercase : function(value){
13671 return String(value).toUpperCase();
13675 * Converts the first character only of a string to upper case
13676 * @param {String} value The text to convert
13677 * @return {String} The converted text
13679 capitalize : function(value){
13680 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13684 call : function(value, fn){
13685 if(arguments.length > 2){
13686 var args = Array.prototype.slice.call(arguments, 2);
13687 args.unshift(value);
13689 return /** eval:var:value */ eval(fn).apply(window, args);
13691 /** eval:var:value */
13692 return /** eval:var:value */ eval(fn).call(window, value);
13698 * safer version of Math.toFixed..??/
13699 * @param {Number/String} value The numeric value to format
13700 * @param {Number/String} value Decimal places
13701 * @return {String} The formatted currency string
13703 toFixed : function(v, n)
13705 // why not use to fixed - precision is buggered???
13707 return Math.round(v-0);
13709 var fact = Math.pow(10,n+1);
13710 v = (Math.round((v-0)*fact))/fact;
13711 var z = (''+fact).substring(2);
13712 if (v == Math.floor(v)) {
13713 return Math.floor(v) + '.' + z;
13716 // now just padd decimals..
13717 var ps = String(v).split('.');
13718 var fd = (ps[1] + z);
13719 var r = fd.substring(0,n);
13720 var rm = fd.substring(n);
13722 return ps[0] + '.' + r;
13724 r*=1; // turn it into a number;
13726 if (String(r).length != n) {
13729 r = String(r).substring(1); // chop the end off.
13732 return ps[0] + '.' + r;
13737 * Format a number as US currency
13738 * @param {Number/String} value The numeric value to format
13739 * @return {String} The formatted currency string
13741 usMoney : function(v){
13742 return '$' + Roo.util.Format.number(v);
13747 * eventually this should probably emulate php's number_format
13748 * @param {Number/String} value The numeric value to format
13749 * @param {Number} decimals number of decimal places
13750 * @return {String} The formatted currency string
13752 number : function(v,decimals)
13754 // multiply and round.
13755 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13756 var mul = Math.pow(10, decimals);
13757 var zero = String(mul).substring(1);
13758 v = (Math.round((v-0)*mul))/mul;
13760 // if it's '0' number.. then
13762 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13764 var ps = v.split('.');
13768 var r = /(\d+)(\d{3})/;
13770 while (r.test(whole)) {
13771 whole = whole.replace(r, '$1' + ',' + '$2');
13777 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13778 // does not have decimals
13779 (decimals ? ('.' + zero) : '');
13782 return whole + sub ;
13786 * Parse a value into a formatted date using the specified format pattern.
13787 * @param {Mixed} value The value to format
13788 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13789 * @return {String} The formatted date string
13791 date : function(v, format){
13795 if(!(v instanceof Date)){
13796 v = new Date(Date.parse(v));
13798 return v.dateFormat(format || Roo.util.Format.defaults.date);
13802 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13803 * @param {String} format Any valid date format string
13804 * @return {Function} The date formatting function
13806 dateRenderer : function(format){
13807 return function(v){
13808 return Roo.util.Format.date(v, format);
13813 stripTagsRE : /<\/?[^>]+>/gi,
13816 * Strips all HTML tags
13817 * @param {Mixed} value The text from which to strip tags
13818 * @return {String} The stripped text
13820 stripTags : function(v){
13821 return !v ? v : String(v).replace(this.stripTagsRE, "");
13825 Roo.util.Format.defaults = {
13829 * Ext JS Library 1.1.1
13830 * Copyright(c) 2006-2007, Ext JS, LLC.
13832 * Originally Released Under LGPL - original licence link has changed is not relivant.
13835 * <script type="text/javascript">
13842 * @class Roo.MasterTemplate
13843 * @extends Roo.Template
13844 * Provides a template that can have child templates. The syntax is:
13846 var t = new Roo.MasterTemplate(
13847 '<select name="{name}">',
13848 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13851 t.add('options', {value: 'foo', text: 'bar'});
13852 // or you can add multiple child elements in one shot
13853 t.addAll('options', [
13854 {value: 'foo', text: 'bar'},
13855 {value: 'foo2', text: 'bar2'},
13856 {value: 'foo3', text: 'bar3'}
13858 // then append, applying the master template values
13859 t.append('my-form', {name: 'my-select'});
13861 * A name attribute for the child template is not required if you have only one child
13862 * template or you want to refer to them by index.
13864 Roo.MasterTemplate = function(){
13865 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13866 this.originalHtml = this.html;
13868 var m, re = this.subTemplateRe;
13871 while(m = re.exec(this.html)){
13872 var name = m[1], content = m[2];
13877 tpl : new Roo.Template(content)
13880 st[name] = st[subIndex];
13882 st[subIndex].tpl.compile();
13883 st[subIndex].tpl.call = this.call.createDelegate(this);
13886 this.subCount = subIndex;
13889 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13891 * The regular expression used to match sub templates
13895 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13898 * Applies the passed values to a child template.
13899 * @param {String/Number} name (optional) The name or index of the child template
13900 * @param {Array/Object} values The values to be applied to the template
13901 * @return {MasterTemplate} this
13903 add : function(name, values){
13904 if(arguments.length == 1){
13905 values = arguments[0];
13908 var s = this.subs[name];
13909 s.buffer[s.buffer.length] = s.tpl.apply(values);
13914 * Applies all the passed values to a child template.
13915 * @param {String/Number} name (optional) The name or index of the child template
13916 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13917 * @param {Boolean} reset (optional) True to reset the template first
13918 * @return {MasterTemplate} this
13920 fill : function(name, values, reset){
13922 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13930 for(var i = 0, len = values.length; i < len; i++){
13931 this.add(name, values[i]);
13937 * Resets the template for reuse
13938 * @return {MasterTemplate} this
13940 reset : function(){
13942 for(var i = 0; i < this.subCount; i++){
13948 applyTemplate : function(values){
13950 var replaceIndex = -1;
13951 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13952 return s[++replaceIndex].buffer.join("");
13954 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13957 apply : function(){
13958 return this.applyTemplate.apply(this, arguments);
13961 compile : function(){return this;}
13965 * Alias for fill().
13968 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13970 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13971 * var tpl = Roo.MasterTemplate.from('element-id');
13972 * @param {String/HTMLElement} el
13973 * @param {Object} config
13976 Roo.MasterTemplate.from = function(el, config){
13977 el = Roo.getDom(el);
13978 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13981 * Ext JS Library 1.1.1
13982 * Copyright(c) 2006-2007, Ext JS, LLC.
13984 * Originally Released Under LGPL - original licence link has changed is not relivant.
13987 * <script type="text/javascript">
13992 * @class Roo.util.CSS
13993 * Utility class for manipulating CSS rules
13996 Roo.util.CSS = function(){
13998 var doc = document;
14000 var camelRe = /(-[a-z])/gi;
14001 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14005 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14006 * tag and appended to the HEAD of the document.
14007 * @param {String|Object} cssText The text containing the css rules
14008 * @param {String} id An id to add to the stylesheet for later removal
14009 * @return {StyleSheet}
14011 createStyleSheet : function(cssText, id){
14013 var head = doc.getElementsByTagName("head")[0];
14014 var nrules = doc.createElement("style");
14015 nrules.setAttribute("type", "text/css");
14017 nrules.setAttribute("id", id);
14019 if (typeof(cssText) != 'string') {
14020 // support object maps..
14021 // not sure if this a good idea..
14022 // perhaps it should be merged with the general css handling
14023 // and handle js style props.
14024 var cssTextNew = [];
14025 for(var n in cssText) {
14027 for(var k in cssText[n]) {
14028 citems.push( k + ' : ' +cssText[n][k] + ';' );
14030 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14033 cssText = cssTextNew.join("\n");
14039 head.appendChild(nrules);
14040 ss = nrules.styleSheet;
14041 ss.cssText = cssText;
14044 nrules.appendChild(doc.createTextNode(cssText));
14046 nrules.cssText = cssText;
14048 head.appendChild(nrules);
14049 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14051 this.cacheStyleSheet(ss);
14056 * Removes a style or link tag by id
14057 * @param {String} id The id of the tag
14059 removeStyleSheet : function(id){
14060 var existing = doc.getElementById(id);
14062 existing.parentNode.removeChild(existing);
14067 * Dynamically swaps an existing stylesheet reference for a new one
14068 * @param {String} id The id of an existing link tag to remove
14069 * @param {String} url The href of the new stylesheet to include
14071 swapStyleSheet : function(id, url){
14072 this.removeStyleSheet(id);
14073 var ss = doc.createElement("link");
14074 ss.setAttribute("rel", "stylesheet");
14075 ss.setAttribute("type", "text/css");
14076 ss.setAttribute("id", id);
14077 ss.setAttribute("href", url);
14078 doc.getElementsByTagName("head")[0].appendChild(ss);
14082 * Refresh the rule cache if you have dynamically added stylesheets
14083 * @return {Object} An object (hash) of rules indexed by selector
14085 refreshCache : function(){
14086 return this.getRules(true);
14090 cacheStyleSheet : function(stylesheet){
14094 try{// try catch for cross domain access issue
14095 var ssRules = stylesheet.cssRules || stylesheet.rules;
14096 for(var j = ssRules.length-1; j >= 0; --j){
14097 rules[ssRules[j].selectorText] = ssRules[j];
14103 * Gets all css rules for the document
14104 * @param {Boolean} refreshCache true to refresh the internal cache
14105 * @return {Object} An object (hash) of rules indexed by selector
14107 getRules : function(refreshCache){
14108 if(rules == null || refreshCache){
14110 var ds = doc.styleSheets;
14111 for(var i =0, len = ds.length; i < len; i++){
14113 this.cacheStyleSheet(ds[i]);
14121 * Gets an an individual CSS rule by selector(s)
14122 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14123 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14124 * @return {CSSRule} The CSS rule or null if one is not found
14126 getRule : function(selector, refreshCache){
14127 var rs = this.getRules(refreshCache);
14128 if(!(selector instanceof Array)){
14129 return rs[selector];
14131 for(var i = 0; i < selector.length; i++){
14132 if(rs[selector[i]]){
14133 return rs[selector[i]];
14141 * Updates a rule property
14142 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14143 * @param {String} property The css property
14144 * @param {String} value The new value for the property
14145 * @return {Boolean} true If a rule was found and updated
14147 updateRule : function(selector, property, value){
14148 if(!(selector instanceof Array)){
14149 var rule = this.getRule(selector);
14151 rule.style[property.replace(camelRe, camelFn)] = value;
14155 for(var i = 0; i < selector.length; i++){
14156 if(this.updateRule(selector[i], property, value)){
14166 * Ext JS Library 1.1.1
14167 * Copyright(c) 2006-2007, Ext JS, LLC.
14169 * Originally Released Under LGPL - original licence link has changed is not relivant.
14172 * <script type="text/javascript">
14178 * @class Roo.util.ClickRepeater
14179 * @extends Roo.util.Observable
14181 * A wrapper class which can be applied to any element. Fires a "click" event while the
14182 * mouse is pressed. The interval between firings may be specified in the config but
14183 * defaults to 10 milliseconds.
14185 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14187 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14188 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14189 * Similar to an autorepeat key delay.
14190 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14191 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14192 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14193 * "interval" and "delay" are ignored. "immediate" is honored.
14194 * @cfg {Boolean} preventDefault True to prevent the default click event
14195 * @cfg {Boolean} stopDefault True to stop the default click event
14198 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14199 * 2007-02-02 jvs Renamed to ClickRepeater
14200 * 2007-02-03 jvs Modifications for FF Mac and Safari
14203 * @param {String/HTMLElement/Element} el The element to listen on
14204 * @param {Object} config
14206 Roo.util.ClickRepeater = function(el, config)
14208 this.el = Roo.get(el);
14209 this.el.unselectable();
14211 Roo.apply(this, config);
14216 * Fires when the mouse button is depressed.
14217 * @param {Roo.util.ClickRepeater} this
14219 "mousedown" : true,
14222 * Fires on a specified interval during the time the element is pressed.
14223 * @param {Roo.util.ClickRepeater} this
14228 * Fires when the mouse key is released.
14229 * @param {Roo.util.ClickRepeater} this
14234 this.el.on("mousedown", this.handleMouseDown, this);
14235 if(this.preventDefault || this.stopDefault){
14236 this.el.on("click", function(e){
14237 if(this.preventDefault){
14238 e.preventDefault();
14240 if(this.stopDefault){
14246 // allow inline handler
14248 this.on("click", this.handler, this.scope || this);
14251 Roo.util.ClickRepeater.superclass.constructor.call(this);
14254 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14257 preventDefault : true,
14258 stopDefault : false,
14262 handleMouseDown : function(){
14263 clearTimeout(this.timer);
14265 if(this.pressClass){
14266 this.el.addClass(this.pressClass);
14268 this.mousedownTime = new Date();
14270 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14271 this.el.on("mouseout", this.handleMouseOut, this);
14273 this.fireEvent("mousedown", this);
14274 this.fireEvent("click", this);
14276 this.timer = this.click.defer(this.delay || this.interval, this);
14280 click : function(){
14281 this.fireEvent("click", this);
14282 this.timer = this.click.defer(this.getInterval(), this);
14286 getInterval: function(){
14287 if(!this.accelerate){
14288 return this.interval;
14290 var pressTime = this.mousedownTime.getElapsed();
14291 if(pressTime < 500){
14293 }else if(pressTime < 1700){
14295 }else if(pressTime < 2600){
14297 }else if(pressTime < 3500){
14299 }else if(pressTime < 4400){
14301 }else if(pressTime < 5300){
14303 }else if(pressTime < 6200){
14311 handleMouseOut : function(){
14312 clearTimeout(this.timer);
14313 if(this.pressClass){
14314 this.el.removeClass(this.pressClass);
14316 this.el.on("mouseover", this.handleMouseReturn, this);
14320 handleMouseReturn : function(){
14321 this.el.un("mouseover", this.handleMouseReturn);
14322 if(this.pressClass){
14323 this.el.addClass(this.pressClass);
14329 handleMouseUp : function(){
14330 clearTimeout(this.timer);
14331 this.el.un("mouseover", this.handleMouseReturn);
14332 this.el.un("mouseout", this.handleMouseOut);
14333 Roo.get(document).un("mouseup", this.handleMouseUp);
14334 this.el.removeClass(this.pressClass);
14335 this.fireEvent("mouseup", this);
14339 * Ext JS Library 1.1.1
14340 * Copyright(c) 2006-2007, Ext JS, LLC.
14342 * Originally Released Under LGPL - original licence link has changed is not relivant.
14345 * <script type="text/javascript">
14350 * @class Roo.KeyNav
14351 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14352 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14353 * way to implement custom navigation schemes for any UI component.</p>
14354 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14355 * pageUp, pageDown, del, home, end. Usage:</p>
14357 var nav = new Roo.KeyNav("my-element", {
14358 "left" : function(e){
14359 this.moveLeft(e.ctrlKey);
14361 "right" : function(e){
14362 this.moveRight(e.ctrlKey);
14364 "enter" : function(e){
14371 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14372 * @param {Object} config The config
14374 Roo.KeyNav = function(el, config){
14375 this.el = Roo.get(el);
14376 Roo.apply(this, config);
14377 if(!this.disabled){
14378 this.disabled = true;
14383 Roo.KeyNav.prototype = {
14385 * @cfg {Boolean} disabled
14386 * True to disable this KeyNav instance (defaults to false)
14390 * @cfg {String} defaultEventAction
14391 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14392 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14393 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14395 defaultEventAction: "stopEvent",
14397 * @cfg {Boolean} forceKeyDown
14398 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14399 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14400 * handle keydown instead of keypress.
14402 forceKeyDown : false,
14405 prepareEvent : function(e){
14406 var k = e.getKey();
14407 var h = this.keyToHandler[k];
14408 //if(h && this[h]){
14409 // e.stopPropagation();
14411 if(Roo.isSafari && h && k >= 37 && k <= 40){
14417 relay : function(e){
14418 var k = e.getKey();
14419 var h = this.keyToHandler[k];
14421 if(this.doRelay(e, this[h], h) !== true){
14422 e[this.defaultEventAction]();
14428 doRelay : function(e, h, hname){
14429 return h.call(this.scope || this, e);
14432 // possible handlers
14446 // quick lookup hash
14463 * Enable this KeyNav
14465 enable: function(){
14467 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14468 // the EventObject will normalize Safari automatically
14469 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14470 this.el.on("keydown", this.relay, this);
14472 this.el.on("keydown", this.prepareEvent, this);
14473 this.el.on("keypress", this.relay, this);
14475 this.disabled = false;
14480 * Disable this KeyNav
14482 disable: function(){
14483 if(!this.disabled){
14484 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14485 this.el.un("keydown", this.relay);
14487 this.el.un("keydown", this.prepareEvent);
14488 this.el.un("keypress", this.relay);
14490 this.disabled = true;
14495 * Ext JS Library 1.1.1
14496 * Copyright(c) 2006-2007, Ext JS, LLC.
14498 * Originally Released Under LGPL - original licence link has changed is not relivant.
14501 * <script type="text/javascript">
14506 * @class Roo.KeyMap
14507 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14508 * The constructor accepts the same config object as defined by {@link #addBinding}.
14509 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14510 * combination it will call the function with this signature (if the match is a multi-key
14511 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14512 * A KeyMap can also handle a string representation of keys.<br />
14515 // map one key by key code
14516 var map = new Roo.KeyMap("my-element", {
14517 key: 13, // or Roo.EventObject.ENTER
14522 // map multiple keys to one action by string
14523 var map = new Roo.KeyMap("my-element", {
14529 // map multiple keys to multiple actions by strings and array of codes
14530 var map = new Roo.KeyMap("my-element", [
14533 fn: function(){ alert("Return was pressed"); }
14536 fn: function(){ alert('a, b or c was pressed'); }
14541 fn: function(){ alert('Control + shift + tab was pressed.'); }
14545 * <b>Note: A KeyMap starts enabled</b>
14547 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14548 * @param {Object} config The config (see {@link #addBinding})
14549 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14551 Roo.KeyMap = function(el, config, eventName){
14552 this.el = Roo.get(el);
14553 this.eventName = eventName || "keydown";
14554 this.bindings = [];
14556 this.addBinding(config);
14561 Roo.KeyMap.prototype = {
14563 * True to stop the event from bubbling and prevent the default browser action if the
14564 * key was handled by the KeyMap (defaults to false)
14570 * Add a new binding to this KeyMap. The following config object properties are supported:
14572 Property Type Description
14573 ---------- --------------- ----------------------------------------------------------------------
14574 key String/Array A single keycode or an array of keycodes to handle
14575 shift Boolean True to handle key only when shift is pressed (defaults to false)
14576 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14577 alt Boolean True to handle key only when alt is pressed (defaults to false)
14578 fn Function The function to call when KeyMap finds the expected key combination
14579 scope Object The scope of the callback function
14585 var map = new Roo.KeyMap(document, {
14586 key: Roo.EventObject.ENTER,
14591 //Add a new binding to the existing KeyMap later
14599 * @param {Object/Array} config A single KeyMap config or an array of configs
14601 addBinding : function(config){
14602 if(config instanceof Array){
14603 for(var i = 0, len = config.length; i < len; i++){
14604 this.addBinding(config[i]);
14608 var keyCode = config.key,
14609 shift = config.shift,
14610 ctrl = config.ctrl,
14613 scope = config.scope;
14614 if(typeof keyCode == "string"){
14616 var keyString = keyCode.toUpperCase();
14617 for(var j = 0, len = keyString.length; j < len; j++){
14618 ks.push(keyString.charCodeAt(j));
14622 var keyArray = keyCode instanceof Array;
14623 var handler = function(e){
14624 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14625 var k = e.getKey();
14627 for(var i = 0, len = keyCode.length; i < len; i++){
14628 if(keyCode[i] == k){
14629 if(this.stopEvent){
14632 fn.call(scope || window, k, e);
14638 if(this.stopEvent){
14641 fn.call(scope || window, k, e);
14646 this.bindings.push(handler);
14650 * Shorthand for adding a single key listener
14651 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14652 * following options:
14653 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14654 * @param {Function} fn The function to call
14655 * @param {Object} scope (optional) The scope of the function
14657 on : function(key, fn, scope){
14658 var keyCode, shift, ctrl, alt;
14659 if(typeof key == "object" && !(key instanceof Array)){
14678 handleKeyDown : function(e){
14679 if(this.enabled){ //just in case
14680 var b = this.bindings;
14681 for(var i = 0, len = b.length; i < len; i++){
14682 b[i].call(this, e);
14688 * Returns true if this KeyMap is enabled
14689 * @return {Boolean}
14691 isEnabled : function(){
14692 return this.enabled;
14696 * Enables this KeyMap
14698 enable: function(){
14700 this.el.on(this.eventName, this.handleKeyDown, this);
14701 this.enabled = true;
14706 * Disable this KeyMap
14708 disable: function(){
14710 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14711 this.enabled = false;
14716 * Ext JS Library 1.1.1
14717 * Copyright(c) 2006-2007, Ext JS, LLC.
14719 * Originally Released Under LGPL - original licence link has changed is not relivant.
14722 * <script type="text/javascript">
14727 * @class Roo.util.TextMetrics
14728 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14729 * wide, in pixels, a given block of text will be.
14732 Roo.util.TextMetrics = function(){
14736 * Measures the size of the specified text
14737 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14738 * that can affect the size of the rendered text
14739 * @param {String} text The text to measure
14740 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14741 * in order to accurately measure the text height
14742 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14744 measure : function(el, text, fixedWidth){
14746 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14749 shared.setFixedWidth(fixedWidth || 'auto');
14750 return shared.getSize(text);
14754 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14755 * the overhead of multiple calls to initialize the style properties on each measurement.
14756 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14757 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14758 * in order to accurately measure the text height
14759 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14761 createInstance : function(el, fixedWidth){
14762 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14769 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14770 var ml = new Roo.Element(document.createElement('div'));
14771 document.body.appendChild(ml.dom);
14772 ml.position('absolute');
14773 ml.setLeftTop(-1000, -1000);
14777 ml.setWidth(fixedWidth);
14782 * Returns the size of the specified text based on the internal element's style and width properties
14783 * @memberOf Roo.util.TextMetrics.Instance#
14784 * @param {String} text The text to measure
14785 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14787 getSize : function(text){
14789 var s = ml.getSize();
14795 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14796 * that can affect the size of the rendered text
14797 * @memberOf Roo.util.TextMetrics.Instance#
14798 * @param {String/HTMLElement} el The element, dom node or id
14800 bind : function(el){
14802 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14807 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14808 * to set a fixed width in order to accurately measure the text height.
14809 * @memberOf Roo.util.TextMetrics.Instance#
14810 * @param {Number} width The width to set on the element
14812 setFixedWidth : function(width){
14813 ml.setWidth(width);
14817 * Returns the measured width of the specified text
14818 * @memberOf Roo.util.TextMetrics.Instance#
14819 * @param {String} text The text to measure
14820 * @return {Number} width The width in pixels
14822 getWidth : function(text){
14823 ml.dom.style.width = 'auto';
14824 return this.getSize(text).width;
14828 * Returns the measured height of the specified text. For multiline text, be sure to call
14829 * {@link #setFixedWidth} if necessary.
14830 * @memberOf Roo.util.TextMetrics.Instance#
14831 * @param {String} text The text to measure
14832 * @return {Number} height The height in pixels
14834 getHeight : function(text){
14835 return this.getSize(text).height;
14839 instance.bind(bindTo);
14844 // backwards compat
14845 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14847 * Ext JS Library 1.1.1
14848 * Copyright(c) 2006-2007, Ext JS, LLC.
14850 * Originally Released Under LGPL - original licence link has changed is not relivant.
14853 * <script type="text/javascript">
14857 * @class Roo.state.Provider
14858 * Abstract base class for state provider implementations. This class provides methods
14859 * for encoding and decoding <b>typed</b> variables including dates and defines the
14860 * Provider interface.
14862 Roo.state.Provider = function(){
14864 * @event statechange
14865 * Fires when a state change occurs.
14866 * @param {Provider} this This state provider
14867 * @param {String} key The state key which was changed
14868 * @param {String} value The encoded value for the state
14871 "statechange": true
14874 Roo.state.Provider.superclass.constructor.call(this);
14876 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14878 * Returns the current value for a key
14879 * @param {String} name The key name
14880 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14881 * @return {Mixed} The state data
14883 get : function(name, defaultValue){
14884 return typeof this.state[name] == "undefined" ?
14885 defaultValue : this.state[name];
14889 * Clears a value from the state
14890 * @param {String} name The key name
14892 clear : function(name){
14893 delete this.state[name];
14894 this.fireEvent("statechange", this, name, null);
14898 * Sets the value for a key
14899 * @param {String} name The key name
14900 * @param {Mixed} value The value to set
14902 set : function(name, value){
14903 this.state[name] = value;
14904 this.fireEvent("statechange", this, name, value);
14908 * Decodes a string previously encoded with {@link #encodeValue}.
14909 * @param {String} value The value to decode
14910 * @return {Mixed} The decoded value
14912 decodeValue : function(cookie){
14913 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14914 var matches = re.exec(unescape(cookie));
14915 if(!matches || !matches[1]) {
14916 return; // non state cookie
14918 var type = matches[1];
14919 var v = matches[2];
14922 return parseFloat(v);
14924 return new Date(Date.parse(v));
14929 var values = v.split("^");
14930 for(var i = 0, len = values.length; i < len; i++){
14931 all.push(this.decodeValue(values[i]));
14936 var values = v.split("^");
14937 for(var i = 0, len = values.length; i < len; i++){
14938 var kv = values[i].split("=");
14939 all[kv[0]] = this.decodeValue(kv[1]);
14948 * Encodes a value including type information. Decode with {@link #decodeValue}.
14949 * @param {Mixed} value The value to encode
14950 * @return {String} The encoded value
14952 encodeValue : function(v){
14954 if(typeof v == "number"){
14956 }else if(typeof v == "boolean"){
14957 enc = "b:" + (v ? "1" : "0");
14958 }else if(v instanceof Date){
14959 enc = "d:" + v.toGMTString();
14960 }else if(v instanceof Array){
14962 for(var i = 0, len = v.length; i < len; i++){
14963 flat += this.encodeValue(v[i]);
14969 }else if(typeof v == "object"){
14972 if(typeof v[key] != "function"){
14973 flat += key + "=" + this.encodeValue(v[key]) + "^";
14976 enc = "o:" + flat.substring(0, flat.length-1);
14980 return escape(enc);
14986 * Ext JS Library 1.1.1
14987 * Copyright(c) 2006-2007, Ext JS, LLC.
14989 * Originally Released Under LGPL - original licence link has changed is not relivant.
14992 * <script type="text/javascript">
14995 * @class Roo.state.Manager
14996 * This is the global state manager. By default all components that are "state aware" check this class
14997 * for state information if you don't pass them a custom state provider. In order for this class
14998 * to be useful, it must be initialized with a provider when your application initializes.
15000 // in your initialization function
15002 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15004 // supposed you have a {@link Roo.BorderLayout}
15005 var layout = new Roo.BorderLayout(...);
15006 layout.restoreState();
15007 // or a {Roo.BasicDialog}
15008 var dialog = new Roo.BasicDialog(...);
15009 dialog.restoreState();
15013 Roo.state.Manager = function(){
15014 var provider = new Roo.state.Provider();
15018 * Configures the default state provider for your application
15019 * @param {Provider} stateProvider The state provider to set
15021 setProvider : function(stateProvider){
15022 provider = stateProvider;
15026 * Returns the current value for a key
15027 * @param {String} name The key name
15028 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15029 * @return {Mixed} The state data
15031 get : function(key, defaultValue){
15032 return provider.get(key, defaultValue);
15036 * Sets the value for a key
15037 * @param {String} name The key name
15038 * @param {Mixed} value The state data
15040 set : function(key, value){
15041 provider.set(key, value);
15045 * Clears a value from the state
15046 * @param {String} name The key name
15048 clear : function(key){
15049 provider.clear(key);
15053 * Gets the currently configured state provider
15054 * @return {Provider} The state provider
15056 getProvider : function(){
15063 * Ext JS Library 1.1.1
15064 * Copyright(c) 2006-2007, Ext JS, LLC.
15066 * Originally Released Under LGPL - original licence link has changed is not relivant.
15069 * <script type="text/javascript">
15072 * @class Roo.state.CookieProvider
15073 * @extends Roo.state.Provider
15074 * The default Provider implementation which saves state via cookies.
15077 var cp = new Roo.state.CookieProvider({
15079 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15080 domain: "roojs.com"
15082 Roo.state.Manager.setProvider(cp);
15084 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15085 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15086 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15087 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15088 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15089 * domain the page is running on including the 'www' like 'www.roojs.com')
15090 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15092 * Create a new CookieProvider
15093 * @param {Object} config The configuration object
15095 Roo.state.CookieProvider = function(config){
15096 Roo.state.CookieProvider.superclass.constructor.call(this);
15098 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15099 this.domain = null;
15100 this.secure = false;
15101 Roo.apply(this, config);
15102 this.state = this.readCookies();
15105 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15107 set : function(name, value){
15108 if(typeof value == "undefined" || value === null){
15112 this.setCookie(name, value);
15113 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15117 clear : function(name){
15118 this.clearCookie(name);
15119 Roo.state.CookieProvider.superclass.clear.call(this, name);
15123 readCookies : function(){
15125 var c = document.cookie + ";";
15126 var re = /\s?(.*?)=(.*?);/g;
15128 while((matches = re.exec(c)) != null){
15129 var name = matches[1];
15130 var value = matches[2];
15131 if(name && name.substring(0,3) == "ys-"){
15132 cookies[name.substr(3)] = this.decodeValue(value);
15139 setCookie : function(name, value){
15140 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15141 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15142 ((this.path == null) ? "" : ("; path=" + this.path)) +
15143 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15144 ((this.secure == true) ? "; secure" : "");
15148 clearCookie : function(name){
15149 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15150 ((this.path == null) ? "" : ("; path=" + this.path)) +
15151 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15152 ((this.secure == true) ? "; secure" : "");
15156 * Ext JS Library 1.1.1
15157 * Copyright(c) 2006-2007, Ext JS, LLC.
15159 * Originally Released Under LGPL - original licence link has changed is not relivant.
15162 * <script type="text/javascript">
15167 * @class Roo.ComponentMgr
15168 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15171 Roo.ComponentMgr = function(){
15172 var all = new Roo.util.MixedCollection();
15176 * Registers a component.
15177 * @param {Roo.Component} c The component
15179 register : function(c){
15184 * Unregisters a component.
15185 * @param {Roo.Component} c The component
15187 unregister : function(c){
15192 * Returns a component by id
15193 * @param {String} id The component id
15195 get : function(id){
15196 return all.get(id);
15200 * Registers a function that will be called when a specified component is added to ComponentMgr
15201 * @param {String} id The component id
15202 * @param {Funtction} fn The callback function
15203 * @param {Object} scope The scope of the callback
15205 onAvailable : function(id, fn, scope){
15206 all.on("add", function(index, o){
15208 fn.call(scope || o, o);
15209 all.un("add", fn, scope);
15216 * Ext JS Library 1.1.1
15217 * Copyright(c) 2006-2007, Ext JS, LLC.
15219 * Originally Released Under LGPL - original licence link has changed is not relivant.
15222 * <script type="text/javascript">
15226 * @class Roo.Component
15227 * @extends Roo.util.Observable
15228 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15229 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15230 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15231 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15232 * All visual components (widgets) that require rendering into a layout should subclass Component.
15234 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15235 * 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
15236 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15238 Roo.Component = function(config){
15239 config = config || {};
15240 if(config.tagName || config.dom || typeof config == "string"){ // element object
15241 config = {el: config, id: config.id || config};
15243 this.initialConfig = config;
15245 Roo.apply(this, config);
15249 * Fires after the component is disabled.
15250 * @param {Roo.Component} this
15255 * Fires after the component is enabled.
15256 * @param {Roo.Component} this
15260 * @event beforeshow
15261 * Fires before the component is shown. Return false to stop the show.
15262 * @param {Roo.Component} this
15267 * Fires after the component is shown.
15268 * @param {Roo.Component} this
15272 * @event beforehide
15273 * Fires before the component is hidden. Return false to stop the hide.
15274 * @param {Roo.Component} this
15279 * Fires after the component is hidden.
15280 * @param {Roo.Component} this
15284 * @event beforerender
15285 * Fires before the component is rendered. Return false to stop the render.
15286 * @param {Roo.Component} this
15288 beforerender : true,
15291 * Fires after the component is rendered.
15292 * @param {Roo.Component} this
15296 * @event beforedestroy
15297 * Fires before the component is destroyed. Return false to stop the destroy.
15298 * @param {Roo.Component} this
15300 beforedestroy : true,
15303 * Fires after the component is destroyed.
15304 * @param {Roo.Component} this
15309 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15311 Roo.ComponentMgr.register(this);
15312 Roo.Component.superclass.constructor.call(this);
15313 this.initComponent();
15314 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15315 this.render(this.renderTo);
15316 delete this.renderTo;
15321 Roo.Component.AUTO_ID = 1000;
15323 Roo.extend(Roo.Component, Roo.util.Observable, {
15325 * @scope Roo.Component.prototype
15327 * true if this component is hidden. Read-only.
15332 * true if this component is disabled. Read-only.
15337 * true if this component has been rendered. Read-only.
15341 /** @cfg {String} disableClass
15342 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15344 disabledClass : "x-item-disabled",
15345 /** @cfg {Boolean} allowDomMove
15346 * Whether the component can move the Dom node when rendering (defaults to true).
15348 allowDomMove : true,
15349 /** @cfg {String} hideMode (display|visibility)
15350 * How this component should hidden. Supported values are
15351 * "visibility" (css visibility), "offsets" (negative offset position) and
15352 * "display" (css display) - defaults to "display".
15354 hideMode: 'display',
15357 ctype : "Roo.Component",
15360 * @cfg {String} actionMode
15361 * which property holds the element that used for hide() / show() / disable() / enable()
15367 getActionEl : function(){
15368 return this[this.actionMode];
15371 initComponent : Roo.emptyFn,
15373 * If this is a lazy rendering component, render it to its container element.
15374 * @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.
15376 render : function(container, position){
15377 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15378 if(!container && this.el){
15379 this.el = Roo.get(this.el);
15380 container = this.el.dom.parentNode;
15381 this.allowDomMove = false;
15383 this.container = Roo.get(container);
15384 this.rendered = true;
15385 if(position !== undefined){
15386 if(typeof position == 'number'){
15387 position = this.container.dom.childNodes[position];
15389 position = Roo.getDom(position);
15392 this.onRender(this.container, position || null);
15394 this.el.addClass(this.cls);
15398 this.el.applyStyles(this.style);
15401 this.fireEvent("render", this);
15402 this.afterRender(this.container);
15414 // default function is not really useful
15415 onRender : function(ct, position){
15417 this.el = Roo.get(this.el);
15418 if(this.allowDomMove !== false){
15419 ct.dom.insertBefore(this.el.dom, position);
15425 getAutoCreate : function(){
15426 var cfg = typeof this.autoCreate == "object" ?
15427 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15428 if(this.id && !cfg.id){
15435 afterRender : Roo.emptyFn,
15438 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15439 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15441 destroy : function(){
15442 if(this.fireEvent("beforedestroy", this) !== false){
15443 this.purgeListeners();
15444 this.beforeDestroy();
15446 this.el.removeAllListeners();
15448 if(this.actionMode == "container"){
15449 this.container.remove();
15453 Roo.ComponentMgr.unregister(this);
15454 this.fireEvent("destroy", this);
15459 beforeDestroy : function(){
15464 onDestroy : function(){
15469 * Returns the underlying {@link Roo.Element}.
15470 * @return {Roo.Element} The element
15472 getEl : function(){
15477 * Returns the id of this component.
15480 getId : function(){
15485 * Try to focus this component.
15486 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15487 * @return {Roo.Component} this
15489 focus : function(selectText){
15492 if(selectText === true){
15493 this.el.dom.select();
15508 * Disable this component.
15509 * @return {Roo.Component} this
15511 disable : function(){
15515 this.disabled = true;
15516 this.fireEvent("disable", this);
15521 onDisable : function(){
15522 this.getActionEl().addClass(this.disabledClass);
15523 this.el.dom.disabled = true;
15527 * Enable this component.
15528 * @return {Roo.Component} this
15530 enable : function(){
15534 this.disabled = false;
15535 this.fireEvent("enable", this);
15540 onEnable : function(){
15541 this.getActionEl().removeClass(this.disabledClass);
15542 this.el.dom.disabled = false;
15546 * Convenience function for setting disabled/enabled by boolean.
15547 * @param {Boolean} disabled
15549 setDisabled : function(disabled){
15550 this[disabled ? "disable" : "enable"]();
15554 * Show this component.
15555 * @return {Roo.Component} this
15558 if(this.fireEvent("beforeshow", this) !== false){
15559 this.hidden = false;
15563 this.fireEvent("show", this);
15569 onShow : function(){
15570 var ae = this.getActionEl();
15571 if(this.hideMode == 'visibility'){
15572 ae.dom.style.visibility = "visible";
15573 }else if(this.hideMode == 'offsets'){
15574 ae.removeClass('x-hidden');
15576 ae.dom.style.display = "";
15581 * Hide this component.
15582 * @return {Roo.Component} this
15585 if(this.fireEvent("beforehide", this) !== false){
15586 this.hidden = true;
15590 this.fireEvent("hide", this);
15596 onHide : function(){
15597 var ae = this.getActionEl();
15598 if(this.hideMode == 'visibility'){
15599 ae.dom.style.visibility = "hidden";
15600 }else if(this.hideMode == 'offsets'){
15601 ae.addClass('x-hidden');
15603 ae.dom.style.display = "none";
15608 * Convenience function to hide or show this component by boolean.
15609 * @param {Boolean} visible True to show, false to hide
15610 * @return {Roo.Component} this
15612 setVisible: function(visible){
15622 * Returns true if this component is visible.
15624 isVisible : function(){
15625 return this.getActionEl().isVisible();
15628 cloneConfig : function(overrides){
15629 overrides = overrides || {};
15630 var id = overrides.id || Roo.id();
15631 var cfg = Roo.applyIf(overrides, this.initialConfig);
15632 cfg.id = id; // prevent dup id
15633 return new this.constructor(cfg);
15637 * Ext JS Library 1.1.1
15638 * Copyright(c) 2006-2007, Ext JS, LLC.
15640 * Originally Released Under LGPL - original licence link has changed is not relivant.
15643 * <script type="text/javascript">
15647 * @class Roo.BoxComponent
15648 * @extends Roo.Component
15649 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15650 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15651 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15652 * layout containers.
15654 * @param {Roo.Element/String/Object} config The configuration options.
15656 Roo.BoxComponent = function(config){
15657 Roo.Component.call(this, config);
15661 * Fires after the component is resized.
15662 * @param {Roo.Component} this
15663 * @param {Number} adjWidth The box-adjusted width that was set
15664 * @param {Number} adjHeight The box-adjusted height that was set
15665 * @param {Number} rawWidth The width that was originally specified
15666 * @param {Number} rawHeight The height that was originally specified
15671 * Fires after the component is moved.
15672 * @param {Roo.Component} this
15673 * @param {Number} x The new x position
15674 * @param {Number} y The new y position
15680 Roo.extend(Roo.BoxComponent, Roo.Component, {
15681 // private, set in afterRender to signify that the component has been rendered
15683 // private, used to defer height settings to subclasses
15684 deferHeight: false,
15685 /** @cfg {Number} width
15686 * width (optional) size of component
15688 /** @cfg {Number} height
15689 * height (optional) size of component
15693 * Sets the width and height of the component. This method fires the resize event. This method can accept
15694 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15695 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15696 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15697 * @return {Roo.BoxComponent} this
15699 setSize : function(w, h){
15700 // support for standard size objects
15701 if(typeof w == 'object'){
15706 if(!this.boxReady){
15712 // prevent recalcs when not needed
15713 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15716 this.lastSize = {width: w, height: h};
15718 var adj = this.adjustSize(w, h);
15719 var aw = adj.width, ah = adj.height;
15720 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15721 var rz = this.getResizeEl();
15722 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15723 rz.setSize(aw, ah);
15724 }else if(!this.deferHeight && ah !== undefined){
15726 }else if(aw !== undefined){
15729 this.onResize(aw, ah, w, h);
15730 this.fireEvent('resize', this, aw, ah, w, h);
15736 * Gets the current size of the component's underlying element.
15737 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15739 getSize : function(){
15740 return this.el.getSize();
15744 * Gets the current XY position of the component's underlying element.
15745 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15746 * @return {Array} The XY position of the element (e.g., [100, 200])
15748 getPosition : function(local){
15749 if(local === true){
15750 return [this.el.getLeft(true), this.el.getTop(true)];
15752 return this.xy || this.el.getXY();
15756 * Gets the current box measurements of the component's underlying element.
15757 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15758 * @returns {Object} box An object in the format {x, y, width, height}
15760 getBox : function(local){
15761 var s = this.el.getSize();
15763 s.x = this.el.getLeft(true);
15764 s.y = this.el.getTop(true);
15766 var xy = this.xy || this.el.getXY();
15774 * Sets the current box measurements of the component's underlying element.
15775 * @param {Object} box An object in the format {x, y, width, height}
15776 * @returns {Roo.BoxComponent} this
15778 updateBox : function(box){
15779 this.setSize(box.width, box.height);
15780 this.setPagePosition(box.x, box.y);
15785 getResizeEl : function(){
15786 return this.resizeEl || this.el;
15790 getPositionEl : function(){
15791 return this.positionEl || this.el;
15795 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15796 * This method fires the move event.
15797 * @param {Number} left The new left
15798 * @param {Number} top The new top
15799 * @returns {Roo.BoxComponent} this
15801 setPosition : function(x, y){
15804 if(!this.boxReady){
15807 var adj = this.adjustPosition(x, y);
15808 var ax = adj.x, ay = adj.y;
15810 var el = this.getPositionEl();
15811 if(ax !== undefined || ay !== undefined){
15812 if(ax !== undefined && ay !== undefined){
15813 el.setLeftTop(ax, ay);
15814 }else if(ax !== undefined){
15816 }else if(ay !== undefined){
15819 this.onPosition(ax, ay);
15820 this.fireEvent('move', this, ax, ay);
15826 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15827 * This method fires the move event.
15828 * @param {Number} x The new x position
15829 * @param {Number} y The new y position
15830 * @returns {Roo.BoxComponent} this
15832 setPagePosition : function(x, y){
15835 if(!this.boxReady){
15838 if(x === undefined || y === undefined){ // cannot translate undefined points
15841 var p = this.el.translatePoints(x, y);
15842 this.setPosition(p.left, p.top);
15847 onRender : function(ct, position){
15848 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15850 this.resizeEl = Roo.get(this.resizeEl);
15852 if(this.positionEl){
15853 this.positionEl = Roo.get(this.positionEl);
15858 afterRender : function(){
15859 Roo.BoxComponent.superclass.afterRender.call(this);
15860 this.boxReady = true;
15861 this.setSize(this.width, this.height);
15862 if(this.x || this.y){
15863 this.setPosition(this.x, this.y);
15865 if(this.pageX || this.pageY){
15866 this.setPagePosition(this.pageX, this.pageY);
15871 * Force the component's size to recalculate based on the underlying element's current height and width.
15872 * @returns {Roo.BoxComponent} this
15874 syncSize : function(){
15875 delete this.lastSize;
15876 this.setSize(this.el.getWidth(), this.el.getHeight());
15881 * Called after the component is resized, this method is empty by default but can be implemented by any
15882 * subclass that needs to perform custom logic after a resize occurs.
15883 * @param {Number} adjWidth The box-adjusted width that was set
15884 * @param {Number} adjHeight The box-adjusted height that was set
15885 * @param {Number} rawWidth The width that was originally specified
15886 * @param {Number} rawHeight The height that was originally specified
15888 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15893 * Called after the component is moved, this method is empty by default but can be implemented by any
15894 * subclass that needs to perform custom logic after a move occurs.
15895 * @param {Number} x The new x position
15896 * @param {Number} y The new y position
15898 onPosition : function(x, y){
15903 adjustSize : function(w, h){
15904 if(this.autoWidth){
15907 if(this.autoHeight){
15910 return {width : w, height: h};
15914 adjustPosition : function(x, y){
15915 return {x : x, y: y};
15918 * Original code for Roojs - LGPL
15919 * <script type="text/javascript">
15923 * @class Roo.XComponent
15924 * A delayed Element creator...
15925 * Or a way to group chunks of interface together.
15926 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15927 * used in conjunction with XComponent.build() it will create an instance of each element,
15928 * then call addxtype() to build the User interface.
15930 * Mypart.xyx = new Roo.XComponent({
15932 parent : 'Mypart.xyz', // empty == document.element.!!
15936 disabled : function() {}
15938 tree : function() { // return an tree of xtype declared components
15942 xtype : 'NestedLayoutPanel',
15949 * It can be used to build a big heiracy, with parent etc.
15950 * or you can just use this to render a single compoent to a dom element
15951 * MYPART.render(Roo.Element | String(id) | dom_element )
15958 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15959 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15961 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15963 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15964 * - if mulitple topModules exist, the last one is defined as the top module.
15968 * When the top level or multiple modules are to embedded into a existing HTML page,
15969 * the parent element can container '#id' of the element where the module will be drawn.
15973 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15974 * it relies more on a include mechanism, where sub modules are included into an outer page.
15975 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15977 * Bootstrap Roo Included elements
15979 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15980 * hence confusing the component builder as it thinks there are multiple top level elements.
15984 * @extends Roo.util.Observable
15986 * @param cfg {Object} configuration of component
15989 Roo.XComponent = function(cfg) {
15990 Roo.apply(this, cfg);
15994 * Fires when this the componnt is built
15995 * @param {Roo.XComponent} c the component
16000 this.region = this.region || 'center'; // default..
16001 Roo.XComponent.register(this);
16002 this.modules = false;
16003 this.el = false; // where the layout goes..
16007 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16010 * The created element (with Roo.factory())
16011 * @type {Roo.Layout}
16017 * for BC - use el in new code
16018 * @type {Roo.Layout}
16024 * for BC - use el in new code
16025 * @type {Roo.Layout}
16030 * @cfg {Function|boolean} disabled
16031 * If this module is disabled by some rule, return true from the funtion
16036 * @cfg {String} parent
16037 * Name of parent element which it get xtype added to..
16042 * @cfg {String} order
16043 * Used to set the order in which elements are created (usefull for multiple tabs)
16048 * @cfg {String} name
16049 * String to display while loading.
16053 * @cfg {String} region
16054 * Region to render component to (defaults to center)
16059 * @cfg {Array} items
16060 * A single item array - the first element is the root of the tree..
16061 * It's done this way to stay compatible with the Xtype system...
16067 * The method that retuns the tree of parts that make up this compoennt
16074 * render element to dom or tree
16075 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16078 render : function(el)
16082 var hp = this.parent ? 1 : 0;
16083 Roo.debug && Roo.log(this);
16085 var tree = this._tree ? this._tree() : this.tree();
16088 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16089 // if parent is a '#.....' string, then let's use that..
16090 var ename = this.parent.substr(1);
16091 this.parent = false;
16092 Roo.debug && Roo.log(ename);
16094 case 'bootstrap-body':
16095 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16096 // this is the BorderLayout standard?
16097 this.parent = { el : true };
16100 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16101 // need to insert stuff...
16103 el : new Roo.bootstrap.layout.Border({
16104 el : document.body,
16110 tabPosition: 'top',
16111 //resizeTabs: true,
16112 alwaysShowTabs: true,
16122 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16123 this.parent = { el : new Roo.bootstrap.Body() };
16124 Roo.debug && Roo.log("setting el to doc body");
16127 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16131 this.parent = { el : true};
16134 el = Roo.get(ename);
16135 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16136 this.parent = { el : true};
16143 if (!el && !this.parent) {
16144 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16149 Roo.debug && Roo.log("EL:");
16150 Roo.debug && Roo.log(el);
16151 Roo.debug && Roo.log("this.parent.el:");
16152 Roo.debug && Roo.log(this.parent.el);
16155 // altertive root elements ??? - we need a better way to indicate these.
16156 var is_alt = Roo.XComponent.is_alt ||
16157 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16158 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16159 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16163 if (!this.parent && is_alt) {
16164 //el = Roo.get(document.body);
16165 this.parent = { el : true };
16170 if (!this.parent) {
16172 Roo.debug && Roo.log("no parent - creating one");
16174 el = el ? Roo.get(el) : false;
16176 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16179 el : new Roo.bootstrap.layout.Border({
16180 el: el || document.body,
16186 tabPosition: 'top',
16187 //resizeTabs: true,
16188 alwaysShowTabs: false,
16191 overflow: 'visible'
16197 // it's a top level one..
16199 el : new Roo.BorderLayout(el || document.body, {
16204 tabPosition: 'top',
16205 //resizeTabs: true,
16206 alwaysShowTabs: el && hp? false : true,
16207 hideTabs: el || !hp ? true : false,
16215 if (!this.parent.el) {
16216 // probably an old style ctor, which has been disabled.
16220 // The 'tree' method is '_tree now'
16222 tree.region = tree.region || this.region;
16223 var is_body = false;
16224 if (this.parent.el === true) {
16225 // bootstrap... - body..
16229 this.parent.el = Roo.factory(tree);
16233 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16234 this.fireEvent('built', this);
16236 this.panel = this.el;
16237 this.layout = this.panel.layout;
16238 this.parentLayout = this.parent.layout || false;
16244 Roo.apply(Roo.XComponent, {
16246 * @property hideProgress
16247 * true to disable the building progress bar.. usefull on single page renders.
16250 hideProgress : false,
16252 * @property buildCompleted
16253 * True when the builder has completed building the interface.
16256 buildCompleted : false,
16259 * @property topModule
16260 * the upper most module - uses document.element as it's constructor.
16267 * @property modules
16268 * array of modules to be created by registration system.
16269 * @type {Array} of Roo.XComponent
16274 * @property elmodules
16275 * array of modules to be created by which use #ID
16276 * @type {Array} of Roo.XComponent
16283 * Is an alternative Root - normally used by bootstrap or other systems,
16284 * where the top element in the tree can wrap 'body'
16285 * @type {boolean} (default false)
16290 * @property build_from_html
16291 * Build elements from html - used by bootstrap HTML stuff
16292 * - this is cleared after build is completed
16293 * @type {boolean} (default false)
16296 build_from_html : false,
16298 * Register components to be built later.
16300 * This solves the following issues
16301 * - Building is not done on page load, but after an authentication process has occured.
16302 * - Interface elements are registered on page load
16303 * - Parent Interface elements may not be loaded before child, so this handles that..
16310 module : 'Pman.Tab.projectMgr',
16312 parent : 'Pman.layout',
16313 disabled : false, // or use a function..
16316 * * @param {Object} details about module
16318 register : function(obj) {
16320 Roo.XComponent.event.fireEvent('register', obj);
16321 switch(typeof(obj.disabled) ) {
16327 if ( obj.disabled() ) {
16333 if (obj.disabled) {
16339 this.modules.push(obj);
16343 * convert a string to an object..
16344 * eg. 'AAA.BBB' -> finds AAA.BBB
16348 toObject : function(str)
16350 if (!str || typeof(str) == 'object') {
16353 if (str.substring(0,1) == '#') {
16357 var ar = str.split('.');
16362 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16364 throw "Module not found : " + str;
16368 throw "Module not found : " + str;
16370 Roo.each(ar, function(e) {
16371 if (typeof(o[e]) == 'undefined') {
16372 throw "Module not found : " + str;
16383 * move modules into their correct place in the tree..
16386 preBuild : function ()
16389 Roo.each(this.modules , function (obj)
16391 Roo.XComponent.event.fireEvent('beforebuild', obj);
16393 var opar = obj.parent;
16395 obj.parent = this.toObject(opar);
16397 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16402 Roo.debug && Roo.log("GOT top level module");
16403 Roo.debug && Roo.log(obj);
16404 obj.modules = new Roo.util.MixedCollection(false,
16405 function(o) { return o.order + '' }
16407 this.topModule = obj;
16410 // parent is a string (usually a dom element name..)
16411 if (typeof(obj.parent) == 'string') {
16412 this.elmodules.push(obj);
16415 if (obj.parent.constructor != Roo.XComponent) {
16416 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16418 if (!obj.parent.modules) {
16419 obj.parent.modules = new Roo.util.MixedCollection(false,
16420 function(o) { return o.order + '' }
16423 if (obj.parent.disabled) {
16424 obj.disabled = true;
16426 obj.parent.modules.add(obj);
16431 * make a list of modules to build.
16432 * @return {Array} list of modules.
16435 buildOrder : function()
16438 var cmp = function(a,b) {
16439 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16441 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16442 throw "No top level modules to build";
16445 // make a flat list in order of modules to build.
16446 var mods = this.topModule ? [ this.topModule ] : [];
16449 // elmodules (is a list of DOM based modules )
16450 Roo.each(this.elmodules, function(e) {
16452 if (!this.topModule &&
16453 typeof(e.parent) == 'string' &&
16454 e.parent.substring(0,1) == '#' &&
16455 Roo.get(e.parent.substr(1))
16458 _this.topModule = e;
16464 // add modules to their parents..
16465 var addMod = function(m) {
16466 Roo.debug && Roo.log("build Order: add: " + m.name);
16469 if (m.modules && !m.disabled) {
16470 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16471 m.modules.keySort('ASC', cmp );
16472 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16474 m.modules.each(addMod);
16476 Roo.debug && Roo.log("build Order: no child modules");
16478 // not sure if this is used any more..
16480 m.finalize.name = m.name + " (clean up) ";
16481 mods.push(m.finalize);
16485 if (this.topModule && this.topModule.modules) {
16486 this.topModule.modules.keySort('ASC', cmp );
16487 this.topModule.modules.each(addMod);
16493 * Build the registered modules.
16494 * @param {Object} parent element.
16495 * @param {Function} optional method to call after module has been added.
16499 build : function(opts)
16502 if (typeof(opts) != 'undefined') {
16503 Roo.apply(this,opts);
16507 var mods = this.buildOrder();
16509 //this.allmods = mods;
16510 //Roo.debug && Roo.log(mods);
16512 if (!mods.length) { // should not happen
16513 throw "NO modules!!!";
16517 var msg = "Building Interface...";
16518 // flash it up as modal - so we store the mask!?
16519 if (!this.hideProgress && Roo.MessageBox) {
16520 Roo.MessageBox.show({ title: 'loading' });
16521 Roo.MessageBox.show({
16522 title: "Please wait...",
16531 var total = mods.length;
16534 var progressRun = function() {
16535 if (!mods.length) {
16536 Roo.debug && Roo.log('hide?');
16537 if (!this.hideProgress && Roo.MessageBox) {
16538 Roo.MessageBox.hide();
16540 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16542 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16548 var m = mods.shift();
16551 Roo.debug && Roo.log(m);
16552 // not sure if this is supported any more.. - modules that are are just function
16553 if (typeof(m) == 'function') {
16555 return progressRun.defer(10, _this);
16559 msg = "Building Interface " + (total - mods.length) +
16561 (m.name ? (' - ' + m.name) : '');
16562 Roo.debug && Roo.log(msg);
16563 if (!_this.hideProgress && Roo.MessageBox) {
16564 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16568 // is the module disabled?
16569 var disabled = (typeof(m.disabled) == 'function') ?
16570 m.disabled.call(m.module.disabled) : m.disabled;
16574 return progressRun(); // we do not update the display!
16582 // it's 10 on top level, and 1 on others??? why...
16583 return progressRun.defer(10, _this);
16586 progressRun.defer(1, _this);
16600 * wrapper for event.on - aliased later..
16601 * Typically use to register a event handler for register:
16603 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16612 Roo.XComponent.event = new Roo.util.Observable({
16616 * Fires when an Component is registered,
16617 * set the disable property on the Component to stop registration.
16618 * @param {Roo.XComponent} c the component being registerd.
16623 * @event beforebuild
16624 * Fires before each Component is built
16625 * can be used to apply permissions.
16626 * @param {Roo.XComponent} c the component being registerd.
16629 'beforebuild' : true,
16631 * @event buildcomplete
16632 * Fires on the top level element when all elements have been built
16633 * @param {Roo.XComponent} the top level component.
16635 'buildcomplete' : true
16640 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16643 * marked - a markdown parser
16644 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16645 * https://github.com/chjj/marked
16651 * Roo.Markdown - is a very crude wrapper around marked..
16655 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16657 * Note: move the sample code to the bottom of this
16658 * file before uncommenting it.
16663 Roo.Markdown.toHtml = function(text) {
16665 var c = new Roo.Markdown.marked.setOptions({
16666 renderer: new Roo.Markdown.marked.Renderer(),
16677 text = text.replace(/\\\n/g,' ');
16678 return Roo.Markdown.marked(text);
16683 // Wraps all "globals" so that the only thing
16684 // exposed is makeHtml().
16689 * Block-Level Grammar
16694 code: /^( {4}[^\n]+\n*)+/,
16696 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16697 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16699 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16700 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16701 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16702 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16703 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16705 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16709 block.bullet = /(?:[*+-]|\d+\.)/;
16710 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16711 block.item = replace(block.item, 'gm')
16712 (/bull/g, block.bullet)
16715 block.list = replace(block.list)
16716 (/bull/g, block.bullet)
16717 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16718 ('def', '\\n+(?=' + block.def.source + ')')
16721 block.blockquote = replace(block.blockquote)
16725 block._tag = '(?!(?:'
16726 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16727 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16728 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16730 block.html = replace(block.html)
16731 ('comment', /<!--[\s\S]*?-->/)
16732 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16733 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16734 (/tag/g, block._tag)
16737 block.paragraph = replace(block.paragraph)
16739 ('heading', block.heading)
16740 ('lheading', block.lheading)
16741 ('blockquote', block.blockquote)
16742 ('tag', '<' + block._tag)
16747 * Normal Block Grammar
16750 block.normal = merge({}, block);
16753 * GFM Block Grammar
16756 block.gfm = merge({}, block.normal, {
16757 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16759 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16762 block.gfm.paragraph = replace(block.paragraph)
16764 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16765 + block.list.source.replace('\\1', '\\3') + '|')
16769 * GFM + Tables Block Grammar
16772 block.tables = merge({}, block.gfm, {
16773 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16774 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16781 function Lexer(options) {
16783 this.tokens.links = {};
16784 this.options = options || marked.defaults;
16785 this.rules = block.normal;
16787 if (this.options.gfm) {
16788 if (this.options.tables) {
16789 this.rules = block.tables;
16791 this.rules = block.gfm;
16797 * Expose Block Rules
16800 Lexer.rules = block;
16803 * Static Lex Method
16806 Lexer.lex = function(src, options) {
16807 var lexer = new Lexer(options);
16808 return lexer.lex(src);
16815 Lexer.prototype.lex = function(src) {
16817 .replace(/\r\n|\r/g, '\n')
16818 .replace(/\t/g, ' ')
16819 .replace(/\u00a0/g, ' ')
16820 .replace(/\u2424/g, '\n');
16822 return this.token(src, true);
16829 Lexer.prototype.token = function(src, top, bq) {
16830 var src = src.replace(/^ +$/gm, '')
16843 if (cap = this.rules.newline.exec(src)) {
16844 src = src.substring(cap[0].length);
16845 if (cap[0].length > 1) {
16853 if (cap = this.rules.code.exec(src)) {
16854 src = src.substring(cap[0].length);
16855 cap = cap[0].replace(/^ {4}/gm, '');
16858 text: !this.options.pedantic
16859 ? cap.replace(/\n+$/, '')
16866 if (cap = this.rules.fences.exec(src)) {
16867 src = src.substring(cap[0].length);
16877 if (cap = this.rules.heading.exec(src)) {
16878 src = src.substring(cap[0].length);
16881 depth: cap[1].length,
16887 // table no leading pipe (gfm)
16888 if (top && (cap = this.rules.nptable.exec(src))) {
16889 src = src.substring(cap[0].length);
16893 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16894 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16895 cells: cap[3].replace(/\n$/, '').split('\n')
16898 for (i = 0; i < item.align.length; i++) {
16899 if (/^ *-+: *$/.test(item.align[i])) {
16900 item.align[i] = 'right';
16901 } else if (/^ *:-+: *$/.test(item.align[i])) {
16902 item.align[i] = 'center';
16903 } else if (/^ *:-+ *$/.test(item.align[i])) {
16904 item.align[i] = 'left';
16906 item.align[i] = null;
16910 for (i = 0; i < item.cells.length; i++) {
16911 item.cells[i] = item.cells[i].split(/ *\| */);
16914 this.tokens.push(item);
16920 if (cap = this.rules.lheading.exec(src)) {
16921 src = src.substring(cap[0].length);
16924 depth: cap[2] === '=' ? 1 : 2,
16931 if (cap = this.rules.hr.exec(src)) {
16932 src = src.substring(cap[0].length);
16940 if (cap = this.rules.blockquote.exec(src)) {
16941 src = src.substring(cap[0].length);
16944 type: 'blockquote_start'
16947 cap = cap[0].replace(/^ *> ?/gm, '');
16949 // Pass `top` to keep the current
16950 // "toplevel" state. This is exactly
16951 // how markdown.pl works.
16952 this.token(cap, top, true);
16955 type: 'blockquote_end'
16962 if (cap = this.rules.list.exec(src)) {
16963 src = src.substring(cap[0].length);
16967 type: 'list_start',
16968 ordered: bull.length > 1
16971 // Get each top-level item.
16972 cap = cap[0].match(this.rules.item);
16978 for (; i < l; i++) {
16981 // Remove the list item's bullet
16982 // so it is seen as the next token.
16983 space = item.length;
16984 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16986 // Outdent whatever the
16987 // list item contains. Hacky.
16988 if (~item.indexOf('\n ')) {
16989 space -= item.length;
16990 item = !this.options.pedantic
16991 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16992 : item.replace(/^ {1,4}/gm, '');
16995 // Determine whether the next list item belongs here.
16996 // Backpedal if it does not belong in this list.
16997 if (this.options.smartLists && i !== l - 1) {
16998 b = block.bullet.exec(cap[i + 1])[0];
16999 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17000 src = cap.slice(i + 1).join('\n') + src;
17005 // Determine whether item is loose or not.
17006 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17007 // for discount behavior.
17008 loose = next || /\n\n(?!\s*$)/.test(item);
17010 next = item.charAt(item.length - 1) === '\n';
17011 if (!loose) { loose = next; }
17016 ? 'loose_item_start'
17017 : 'list_item_start'
17021 this.token(item, false, bq);
17024 type: 'list_item_end'
17036 if (cap = this.rules.html.exec(src)) {
17037 src = src.substring(cap[0].length);
17039 type: this.options.sanitize
17042 pre: !this.options.sanitizer
17043 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17050 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17051 src = src.substring(cap[0].length);
17052 this.tokens.links[cap[1].toLowerCase()] = {
17060 if (top && (cap = this.rules.table.exec(src))) {
17061 src = src.substring(cap[0].length);
17065 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17066 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17067 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17070 for (i = 0; i < item.align.length; i++) {
17071 if (/^ *-+: *$/.test(item.align[i])) {
17072 item.align[i] = 'right';
17073 } else if (/^ *:-+: *$/.test(item.align[i])) {
17074 item.align[i] = 'center';
17075 } else if (/^ *:-+ *$/.test(item.align[i])) {
17076 item.align[i] = 'left';
17078 item.align[i] = null;
17082 for (i = 0; i < item.cells.length; i++) {
17083 item.cells[i] = item.cells[i]
17084 .replace(/^ *\| *| *\| *$/g, '')
17088 this.tokens.push(item);
17093 // top-level paragraph
17094 if (top && (cap = this.rules.paragraph.exec(src))) {
17095 src = src.substring(cap[0].length);
17098 text: cap[1].charAt(cap[1].length - 1) === '\n'
17099 ? cap[1].slice(0, -1)
17106 if (cap = this.rules.text.exec(src)) {
17107 // Top-level should never reach here.
17108 src = src.substring(cap[0].length);
17118 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17122 return this.tokens;
17126 * Inline-Level Grammar
17130 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17131 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17133 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17134 link: /^!?\[(inside)\]\(href\)/,
17135 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17136 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17137 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17138 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17139 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17140 br: /^ {2,}\n(?!\s*$)/,
17142 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17145 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17146 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17148 inline.link = replace(inline.link)
17149 ('inside', inline._inside)
17150 ('href', inline._href)
17153 inline.reflink = replace(inline.reflink)
17154 ('inside', inline._inside)
17158 * Normal Inline Grammar
17161 inline.normal = merge({}, inline);
17164 * Pedantic Inline Grammar
17167 inline.pedantic = merge({}, inline.normal, {
17168 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17169 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17173 * GFM Inline Grammar
17176 inline.gfm = merge({}, inline.normal, {
17177 escape: replace(inline.escape)('])', '~|])')(),
17178 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17179 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17180 text: replace(inline.text)
17182 ('|', '|https?://|')
17187 * GFM + Line Breaks Inline Grammar
17190 inline.breaks = merge({}, inline.gfm, {
17191 br: replace(inline.br)('{2,}', '*')(),
17192 text: replace(inline.gfm.text)('{2,}', '*')()
17196 * Inline Lexer & Compiler
17199 function InlineLexer(links, options) {
17200 this.options = options || marked.defaults;
17201 this.links = links;
17202 this.rules = inline.normal;
17203 this.renderer = this.options.renderer || new Renderer;
17204 this.renderer.options = this.options;
17208 Error('Tokens array requires a `links` property.');
17211 if (this.options.gfm) {
17212 if (this.options.breaks) {
17213 this.rules = inline.breaks;
17215 this.rules = inline.gfm;
17217 } else if (this.options.pedantic) {
17218 this.rules = inline.pedantic;
17223 * Expose Inline Rules
17226 InlineLexer.rules = inline;
17229 * Static Lexing/Compiling Method
17232 InlineLexer.output = function(src, links, options) {
17233 var inline = new InlineLexer(links, options);
17234 return inline.output(src);
17241 InlineLexer.prototype.output = function(src) {
17250 if (cap = this.rules.escape.exec(src)) {
17251 src = src.substring(cap[0].length);
17257 if (cap = this.rules.autolink.exec(src)) {
17258 src = src.substring(cap[0].length);
17259 if (cap[2] === '@') {
17260 text = cap[1].charAt(6) === ':'
17261 ? this.mangle(cap[1].substring(7))
17262 : this.mangle(cap[1]);
17263 href = this.mangle('mailto:') + text;
17265 text = escape(cap[1]);
17268 out += this.renderer.link(href, null, text);
17273 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17274 src = src.substring(cap[0].length);
17275 text = escape(cap[1]);
17277 out += this.renderer.link(href, null, text);
17282 if (cap = this.rules.tag.exec(src)) {
17283 if (!this.inLink && /^<a /i.test(cap[0])) {
17284 this.inLink = true;
17285 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17286 this.inLink = false;
17288 src = src.substring(cap[0].length);
17289 out += this.options.sanitize
17290 ? this.options.sanitizer
17291 ? this.options.sanitizer(cap[0])
17298 if (cap = this.rules.link.exec(src)) {
17299 src = src.substring(cap[0].length);
17300 this.inLink = true;
17301 out += this.outputLink(cap, {
17305 this.inLink = false;
17310 if ((cap = this.rules.reflink.exec(src))
17311 || (cap = this.rules.nolink.exec(src))) {
17312 src = src.substring(cap[0].length);
17313 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17314 link = this.links[link.toLowerCase()];
17315 if (!link || !link.href) {
17316 out += cap[0].charAt(0);
17317 src = cap[0].substring(1) + src;
17320 this.inLink = true;
17321 out += this.outputLink(cap, link);
17322 this.inLink = false;
17327 if (cap = this.rules.strong.exec(src)) {
17328 src = src.substring(cap[0].length);
17329 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17334 if (cap = this.rules.em.exec(src)) {
17335 src = src.substring(cap[0].length);
17336 out += this.renderer.em(this.output(cap[2] || cap[1]));
17341 if (cap = this.rules.code.exec(src)) {
17342 src = src.substring(cap[0].length);
17343 out += this.renderer.codespan(escape(cap[2], true));
17348 if (cap = this.rules.br.exec(src)) {
17349 src = src.substring(cap[0].length);
17350 out += this.renderer.br();
17355 if (cap = this.rules.del.exec(src)) {
17356 src = src.substring(cap[0].length);
17357 out += this.renderer.del(this.output(cap[1]));
17362 if (cap = this.rules.text.exec(src)) {
17363 src = src.substring(cap[0].length);
17364 out += this.renderer.text(escape(this.smartypants(cap[0])));
17370 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17381 InlineLexer.prototype.outputLink = function(cap, link) {
17382 var href = escape(link.href)
17383 , title = link.title ? escape(link.title) : null;
17385 return cap[0].charAt(0) !== '!'
17386 ? this.renderer.link(href, title, this.output(cap[1]))
17387 : this.renderer.image(href, title, escape(cap[1]));
17391 * Smartypants Transformations
17394 InlineLexer.prototype.smartypants = function(text) {
17395 if (!this.options.smartypants) { return text; }
17398 .replace(/---/g, '\u2014')
17400 .replace(/--/g, '\u2013')
17402 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17403 // closing singles & apostrophes
17404 .replace(/'/g, '\u2019')
17406 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17408 .replace(/"/g, '\u201d')
17410 .replace(/\.{3}/g, '\u2026');
17417 InlineLexer.prototype.mangle = function(text) {
17418 if (!this.options.mangle) { return text; }
17424 for (; i < l; i++) {
17425 ch = text.charCodeAt(i);
17426 if (Math.random() > 0.5) {
17427 ch = 'x' + ch.toString(16);
17429 out += '&#' + ch + ';';
17439 function Renderer(options) {
17440 this.options = options || {};
17443 Renderer.prototype.code = function(code, lang, escaped) {
17444 if (this.options.highlight) {
17445 var out = this.options.highlight(code, lang);
17446 if (out != null && out !== code) {
17451 // hack!!! - it's already escapeD?
17456 return '<pre><code>'
17457 + (escaped ? code : escape(code, true))
17458 + '\n</code></pre>';
17461 return '<pre><code class="'
17462 + this.options.langPrefix
17463 + escape(lang, true)
17465 + (escaped ? code : escape(code, true))
17466 + '\n</code></pre>\n';
17469 Renderer.prototype.blockquote = function(quote) {
17470 return '<blockquote>\n' + quote + '</blockquote>\n';
17473 Renderer.prototype.html = function(html) {
17477 Renderer.prototype.heading = function(text, level, raw) {
17481 + this.options.headerPrefix
17482 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17490 Renderer.prototype.hr = function() {
17491 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17494 Renderer.prototype.list = function(body, ordered) {
17495 var type = ordered ? 'ol' : 'ul';
17496 return '<' + type + '>\n' + body + '</' + type + '>\n';
17499 Renderer.prototype.listitem = function(text) {
17500 return '<li>' + text + '</li>\n';
17503 Renderer.prototype.paragraph = function(text) {
17504 return '<p>' + text + '</p>\n';
17507 Renderer.prototype.table = function(header, body) {
17508 return '<table class="table table-striped">\n'
17518 Renderer.prototype.tablerow = function(content) {
17519 return '<tr>\n' + content + '</tr>\n';
17522 Renderer.prototype.tablecell = function(content, flags) {
17523 var type = flags.header ? 'th' : 'td';
17524 var tag = flags.align
17525 ? '<' + type + ' style="text-align:' + flags.align + '">'
17526 : '<' + type + '>';
17527 return tag + content + '</' + type + '>\n';
17530 // span level renderer
17531 Renderer.prototype.strong = function(text) {
17532 return '<strong>' + text + '</strong>';
17535 Renderer.prototype.em = function(text) {
17536 return '<em>' + text + '</em>';
17539 Renderer.prototype.codespan = function(text) {
17540 return '<code>' + text + '</code>';
17543 Renderer.prototype.br = function() {
17544 return this.options.xhtml ? '<br/>' : '<br>';
17547 Renderer.prototype.del = function(text) {
17548 return '<del>' + text + '</del>';
17551 Renderer.prototype.link = function(href, title, text) {
17552 if (this.options.sanitize) {
17554 var prot = decodeURIComponent(unescape(href))
17555 .replace(/[^\w:]/g, '')
17560 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17564 var out = '<a href="' + href + '"';
17566 out += ' title="' + title + '"';
17568 out += '>' + text + '</a>';
17572 Renderer.prototype.image = function(href, title, text) {
17573 var out = '<img src="' + href + '" alt="' + text + '"';
17575 out += ' title="' + title + '"';
17577 out += this.options.xhtml ? '/>' : '>';
17581 Renderer.prototype.text = function(text) {
17586 * Parsing & Compiling
17589 function Parser(options) {
17592 this.options = options || marked.defaults;
17593 this.options.renderer = this.options.renderer || new Renderer;
17594 this.renderer = this.options.renderer;
17595 this.renderer.options = this.options;
17599 * Static Parse Method
17602 Parser.parse = function(src, options, renderer) {
17603 var parser = new Parser(options, renderer);
17604 return parser.parse(src);
17611 Parser.prototype.parse = function(src) {
17612 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17613 this.tokens = src.reverse();
17616 while (this.next()) {
17627 Parser.prototype.next = function() {
17628 return this.token = this.tokens.pop();
17632 * Preview Next Token
17635 Parser.prototype.peek = function() {
17636 return this.tokens[this.tokens.length - 1] || 0;
17640 * Parse Text Tokens
17643 Parser.prototype.parseText = function() {
17644 var body = this.token.text;
17646 while (this.peek().type === 'text') {
17647 body += '\n' + this.next().text;
17650 return this.inline.output(body);
17654 * Parse Current Token
17657 Parser.prototype.tok = function() {
17658 switch (this.token.type) {
17663 return this.renderer.hr();
17666 return this.renderer.heading(
17667 this.inline.output(this.token.text),
17672 return this.renderer.code(this.token.text,
17674 this.token.escaped);
17687 for (i = 0; i < this.token.header.length; i++) {
17688 flags = { header: true, align: this.token.align[i] };
17689 cell += this.renderer.tablecell(
17690 this.inline.output(this.token.header[i]),
17691 { header: true, align: this.token.align[i] }
17694 header += this.renderer.tablerow(cell);
17696 for (i = 0; i < this.token.cells.length; i++) {
17697 row = this.token.cells[i];
17700 for (j = 0; j < row.length; j++) {
17701 cell += this.renderer.tablecell(
17702 this.inline.output(row[j]),
17703 { header: false, align: this.token.align[j] }
17707 body += this.renderer.tablerow(cell);
17709 return this.renderer.table(header, body);
17711 case 'blockquote_start': {
17714 while (this.next().type !== 'blockquote_end') {
17715 body += this.tok();
17718 return this.renderer.blockquote(body);
17720 case 'list_start': {
17722 , ordered = this.token.ordered;
17724 while (this.next().type !== 'list_end') {
17725 body += this.tok();
17728 return this.renderer.list(body, ordered);
17730 case 'list_item_start': {
17733 while (this.next().type !== 'list_item_end') {
17734 body += this.token.type === 'text'
17739 return this.renderer.listitem(body);
17741 case 'loose_item_start': {
17744 while (this.next().type !== 'list_item_end') {
17745 body += this.tok();
17748 return this.renderer.listitem(body);
17751 var html = !this.token.pre && !this.options.pedantic
17752 ? this.inline.output(this.token.text)
17754 return this.renderer.html(html);
17756 case 'paragraph': {
17757 return this.renderer.paragraph(this.inline.output(this.token.text));
17760 return this.renderer.paragraph(this.parseText());
17769 function escape(html, encode) {
17771 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17772 .replace(/</g, '<')
17773 .replace(/>/g, '>')
17774 .replace(/"/g, '"')
17775 .replace(/'/g, ''');
17778 function unescape(html) {
17779 // explicitly match decimal, hex, and named HTML entities
17780 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17781 n = n.toLowerCase();
17782 if (n === 'colon') { return ':'; }
17783 if (n.charAt(0) === '#') {
17784 return n.charAt(1) === 'x'
17785 ? String.fromCharCode(parseInt(n.substring(2), 16))
17786 : String.fromCharCode(+n.substring(1));
17792 function replace(regex, opt) {
17793 regex = regex.source;
17795 return function self(name, val) {
17796 if (!name) { return new RegExp(regex, opt); }
17797 val = val.source || val;
17798 val = val.replace(/(^|[^\[])\^/g, '$1');
17799 regex = regex.replace(name, val);
17807 function merge(obj) {
17812 for (; i < arguments.length; i++) {
17813 target = arguments[i];
17814 for (key in target) {
17815 if (Object.prototype.hasOwnProperty.call(target, key)) {
17816 obj[key] = target[key];
17829 function marked(src, opt, callback) {
17830 if (callback || typeof opt === 'function') {
17836 opt = merge({}, marked.defaults, opt || {});
17838 var highlight = opt.highlight
17844 tokens = Lexer.lex(src, opt)
17846 return callback(e);
17849 pending = tokens.length;
17851 var done = function(err) {
17853 opt.highlight = highlight;
17854 return callback(err);
17860 out = Parser.parse(tokens, opt);
17865 opt.highlight = highlight;
17869 : callback(null, out);
17872 if (!highlight || highlight.length < 3) {
17876 delete opt.highlight;
17878 if (!pending) { return done(); }
17880 for (; i < tokens.length; i++) {
17882 if (token.type !== 'code') {
17883 return --pending || done();
17885 return highlight(token.text, token.lang, function(err, code) {
17886 if (err) { return done(err); }
17887 if (code == null || code === token.text) {
17888 return --pending || done();
17891 token.escaped = true;
17892 --pending || done();
17900 if (opt) { opt = merge({}, marked.defaults, opt); }
17901 return Parser.parse(Lexer.lex(src, opt), opt);
17903 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17904 if ((opt || marked.defaults).silent) {
17905 return '<p>An error occured:</p><pre>'
17906 + escape(e.message + '', true)
17918 marked.setOptions = function(opt) {
17919 merge(marked.defaults, opt);
17923 marked.defaults = {
17934 langPrefix: 'lang-',
17935 smartypants: false,
17937 renderer: new Renderer,
17945 marked.Parser = Parser;
17946 marked.parser = Parser.parse;
17948 marked.Renderer = Renderer;
17950 marked.Lexer = Lexer;
17951 marked.lexer = Lexer.lex;
17953 marked.InlineLexer = InlineLexer;
17954 marked.inlineLexer = InlineLexer.output;
17956 marked.parse = marked;
17958 Roo.Markdown.marked = marked;
17962 * Ext JS Library 1.1.1
17963 * Copyright(c) 2006-2007, Ext JS, LLC.
17965 * Originally Released Under LGPL - original licence link has changed is not relivant.
17968 * <script type="text/javascript">
17974 * These classes are derivatives of the similarly named classes in the YUI Library.
17975 * The original license:
17976 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17977 * Code licensed under the BSD License:
17978 * http://developer.yahoo.net/yui/license.txt
17983 var Event=Roo.EventManager;
17984 var Dom=Roo.lib.Dom;
17987 * @class Roo.dd.DragDrop
17988 * @extends Roo.util.Observable
17989 * Defines the interface and base operation of items that that can be
17990 * dragged or can be drop targets. It was designed to be extended, overriding
17991 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17992 * Up to three html elements can be associated with a DragDrop instance:
17994 * <li>linked element: the element that is passed into the constructor.
17995 * This is the element which defines the boundaries for interaction with
17996 * other DragDrop objects.</li>
17997 * <li>handle element(s): The drag operation only occurs if the element that
17998 * was clicked matches a handle element. By default this is the linked
17999 * element, but there are times that you will want only a portion of the
18000 * linked element to initiate the drag operation, and the setHandleElId()
18001 * method provides a way to define this.</li>
18002 * <li>drag element: this represents the element that would be moved along
18003 * with the cursor during a drag operation. By default, this is the linked
18004 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18005 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18008 * This class should not be instantiated until the onload event to ensure that
18009 * the associated elements are available.
18010 * The following would define a DragDrop obj that would interact with any
18011 * other DragDrop obj in the "group1" group:
18013 * dd = new Roo.dd.DragDrop("div1", "group1");
18015 * Since none of the event handlers have been implemented, nothing would
18016 * actually happen if you were to run the code above. Normally you would
18017 * override this class or one of the default implementations, but you can
18018 * also override the methods you want on an instance of the class...
18020 * dd.onDragDrop = function(e, id) {
18021 * alert("dd was dropped on " + id);
18025 * @param {String} id of the element that is linked to this instance
18026 * @param {String} sGroup the group of related DragDrop objects
18027 * @param {object} config an object containing configurable attributes
18028 * Valid properties for DragDrop:
18029 * padding, isTarget, maintainOffset, primaryButtonOnly
18031 Roo.dd.DragDrop = function(id, sGroup, config) {
18033 this.init(id, sGroup, config);
18038 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18041 * The id of the element associated with this object. This is what we
18042 * refer to as the "linked element" because the size and position of
18043 * this element is used to determine when the drag and drop objects have
18051 * Configuration attributes passed into the constructor
18058 * The id of the element that will be dragged. By default this is same
18059 * as the linked element , but could be changed to another element. Ex:
18061 * @property dragElId
18068 * the id of the element that initiates the drag operation. By default
18069 * this is the linked element, but could be changed to be a child of this
18070 * element. This lets us do things like only starting the drag when the
18071 * header element within the linked html element is clicked.
18072 * @property handleElId
18079 * An associative array of HTML tags that will be ignored if clicked.
18080 * @property invalidHandleTypes
18081 * @type {string: string}
18083 invalidHandleTypes: null,
18086 * An associative array of ids for elements that will be ignored if clicked
18087 * @property invalidHandleIds
18088 * @type {string: string}
18090 invalidHandleIds: null,
18093 * An indexted array of css class names for elements that will be ignored
18095 * @property invalidHandleClasses
18098 invalidHandleClasses: null,
18101 * The linked element's absolute X position at the time the drag was
18103 * @property startPageX
18110 * The linked element's absolute X position at the time the drag was
18112 * @property startPageY
18119 * The group defines a logical collection of DragDrop objects that are
18120 * related. Instances only get events when interacting with other
18121 * DragDrop object in the same group. This lets us define multiple
18122 * groups using a single DragDrop subclass if we want.
18124 * @type {string: string}
18129 * Individual drag/drop instances can be locked. This will prevent
18130 * onmousedown start drag.
18138 * Lock this instance
18141 lock: function() { this.locked = true; },
18144 * Unlock this instace
18147 unlock: function() { this.locked = false; },
18150 * By default, all insances can be a drop target. This can be disabled by
18151 * setting isTarget to false.
18158 * The padding configured for this drag and drop object for calculating
18159 * the drop zone intersection with this object.
18166 * Cached reference to the linked element
18167 * @property _domRef
18173 * Internal typeof flag
18174 * @property __ygDragDrop
18177 __ygDragDrop: true,
18180 * Set to true when horizontal contraints are applied
18181 * @property constrainX
18188 * Set to true when vertical contraints are applied
18189 * @property constrainY
18196 * The left constraint
18204 * The right constraint
18212 * The up constraint
18221 * The down constraint
18229 * Maintain offsets when we resetconstraints. Set to true when you want
18230 * the position of the element relative to its parent to stay the same
18231 * when the page changes
18233 * @property maintainOffset
18236 maintainOffset: false,
18239 * Array of pixel locations the element will snap to if we specified a
18240 * horizontal graduation/interval. This array is generated automatically
18241 * when you define a tick interval.
18248 * Array of pixel locations the element will snap to if we specified a
18249 * vertical graduation/interval. This array is generated automatically
18250 * when you define a tick interval.
18257 * By default the drag and drop instance will only respond to the primary
18258 * button click (left button for a right-handed mouse). Set to true to
18259 * allow drag and drop to start with any mouse click that is propogated
18261 * @property primaryButtonOnly
18264 primaryButtonOnly: true,
18267 * The availabe property is false until the linked dom element is accessible.
18268 * @property available
18274 * By default, drags can only be initiated if the mousedown occurs in the
18275 * region the linked element is. This is done in part to work around a
18276 * bug in some browsers that mis-report the mousedown if the previous
18277 * mouseup happened outside of the window. This property is set to true
18278 * if outer handles are defined.
18280 * @property hasOuterHandles
18284 hasOuterHandles: false,
18287 * Code that executes immediately before the startDrag event
18288 * @method b4StartDrag
18291 b4StartDrag: function(x, y) { },
18294 * Abstract method called after a drag/drop object is clicked
18295 * and the drag or mousedown time thresholds have beeen met.
18296 * @method startDrag
18297 * @param {int} X click location
18298 * @param {int} Y click location
18300 startDrag: function(x, y) { /* override this */ },
18303 * Code that executes immediately before the onDrag event
18307 b4Drag: function(e) { },
18310 * Abstract method called during the onMouseMove event while dragging an
18313 * @param {Event} e the mousemove event
18315 onDrag: function(e) { /* override this */ },
18318 * Abstract method called when this element fist begins hovering over
18319 * another DragDrop obj
18320 * @method onDragEnter
18321 * @param {Event} e the mousemove event
18322 * @param {String|DragDrop[]} id In POINT mode, the element
18323 * id this is hovering over. In INTERSECT mode, an array of one or more
18324 * dragdrop items being hovered over.
18326 onDragEnter: function(e, id) { /* override this */ },
18329 * Code that executes immediately before the onDragOver event
18330 * @method b4DragOver
18333 b4DragOver: function(e) { },
18336 * Abstract method called when this element is hovering over another
18338 * @method onDragOver
18339 * @param {Event} e the mousemove event
18340 * @param {String|DragDrop[]} id In POINT mode, the element
18341 * id this is hovering over. In INTERSECT mode, an array of dd items
18342 * being hovered over.
18344 onDragOver: function(e, id) { /* override this */ },
18347 * Code that executes immediately before the onDragOut event
18348 * @method b4DragOut
18351 b4DragOut: function(e) { },
18354 * Abstract method called when we are no longer hovering over an element
18355 * @method onDragOut
18356 * @param {Event} e the mousemove event
18357 * @param {String|DragDrop[]} id In POINT mode, the element
18358 * id this was hovering over. In INTERSECT mode, an array of dd items
18359 * that the mouse is no longer over.
18361 onDragOut: function(e, id) { /* override this */ },
18364 * Code that executes immediately before the onDragDrop event
18365 * @method b4DragDrop
18368 b4DragDrop: function(e) { },
18371 * Abstract method called when this item is dropped on another DragDrop
18373 * @method onDragDrop
18374 * @param {Event} e the mouseup event
18375 * @param {String|DragDrop[]} id In POINT mode, the element
18376 * id this was dropped on. In INTERSECT mode, an array of dd items this
18379 onDragDrop: function(e, id) { /* override this */ },
18382 * Abstract method called when this item is dropped on an area with no
18384 * @method onInvalidDrop
18385 * @param {Event} e the mouseup event
18387 onInvalidDrop: function(e) { /* override this */ },
18390 * Code that executes immediately before the endDrag event
18391 * @method b4EndDrag
18394 b4EndDrag: function(e) { },
18397 * Fired when we are done dragging the object
18399 * @param {Event} e the mouseup event
18401 endDrag: function(e) { /* override this */ },
18404 * Code executed immediately before the onMouseDown event
18405 * @method b4MouseDown
18406 * @param {Event} e the mousedown event
18409 b4MouseDown: function(e) { },
18412 * Event handler that fires when a drag/drop obj gets a mousedown
18413 * @method onMouseDown
18414 * @param {Event} e the mousedown event
18416 onMouseDown: function(e) { /* override this */ },
18419 * Event handler that fires when a drag/drop obj gets a mouseup
18420 * @method onMouseUp
18421 * @param {Event} e the mouseup event
18423 onMouseUp: function(e) { /* override this */ },
18426 * Override the onAvailable method to do what is needed after the initial
18427 * position was determined.
18428 * @method onAvailable
18430 onAvailable: function () {
18434 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18437 defaultPadding : {left:0, right:0, top:0, bottom:0},
18440 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18444 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18445 { dragElId: "existingProxyDiv" });
18446 dd.startDrag = function(){
18447 this.constrainTo("parent-id");
18450 * Or you can initalize it using the {@link Roo.Element} object:
18452 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18453 startDrag : function(){
18454 this.constrainTo("parent-id");
18458 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18459 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18460 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18461 * an object containing the sides to pad. For example: {right:10, bottom:10}
18462 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18464 constrainTo : function(constrainTo, pad, inContent){
18465 if(typeof pad == "number"){
18466 pad = {left: pad, right:pad, top:pad, bottom:pad};
18468 pad = pad || this.defaultPadding;
18469 var b = Roo.get(this.getEl()).getBox();
18470 var ce = Roo.get(constrainTo);
18471 var s = ce.getScroll();
18472 var c, cd = ce.dom;
18473 if(cd == document.body){
18474 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18477 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18481 var topSpace = b.y - c.y;
18482 var leftSpace = b.x - c.x;
18484 this.resetConstraints();
18485 this.setXConstraint(leftSpace - (pad.left||0), // left
18486 c.width - leftSpace - b.width - (pad.right||0) //right
18488 this.setYConstraint(topSpace - (pad.top||0), //top
18489 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18494 * Returns a reference to the linked element
18496 * @return {HTMLElement} the html element
18498 getEl: function() {
18499 if (!this._domRef) {
18500 this._domRef = Roo.getDom(this.id);
18503 return this._domRef;
18507 * Returns a reference to the actual element to drag. By default this is
18508 * the same as the html element, but it can be assigned to another
18509 * element. An example of this can be found in Roo.dd.DDProxy
18510 * @method getDragEl
18511 * @return {HTMLElement} the html element
18513 getDragEl: function() {
18514 return Roo.getDom(this.dragElId);
18518 * Sets up the DragDrop object. Must be called in the constructor of any
18519 * Roo.dd.DragDrop subclass
18521 * @param id the id of the linked element
18522 * @param {String} sGroup the group of related items
18523 * @param {object} config configuration attributes
18525 init: function(id, sGroup, config) {
18526 this.initTarget(id, sGroup, config);
18527 if (!Roo.isTouch) {
18528 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18530 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18531 // Event.on(this.id, "selectstart", Event.preventDefault);
18535 * Initializes Targeting functionality only... the object does not
18536 * get a mousedown handler.
18537 * @method initTarget
18538 * @param id the id of the linked element
18539 * @param {String} sGroup the group of related items
18540 * @param {object} config configuration attributes
18542 initTarget: function(id, sGroup, config) {
18544 // configuration attributes
18545 this.config = config || {};
18547 // create a local reference to the drag and drop manager
18548 this.DDM = Roo.dd.DDM;
18549 // initialize the groups array
18552 // assume that we have an element reference instead of an id if the
18553 // parameter is not a string
18554 if (typeof id !== "string") {
18561 // add to an interaction group
18562 this.addToGroup((sGroup) ? sGroup : "default");
18564 // We don't want to register this as the handle with the manager
18565 // so we just set the id rather than calling the setter.
18566 this.handleElId = id;
18568 // the linked element is the element that gets dragged by default
18569 this.setDragElId(id);
18571 // by default, clicked anchors will not start drag operations.
18572 this.invalidHandleTypes = { A: "A" };
18573 this.invalidHandleIds = {};
18574 this.invalidHandleClasses = [];
18576 this.applyConfig();
18578 this.handleOnAvailable();
18582 * Applies the configuration parameters that were passed into the constructor.
18583 * This is supposed to happen at each level through the inheritance chain. So
18584 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18585 * DragDrop in order to get all of the parameters that are available in
18587 * @method applyConfig
18589 applyConfig: function() {
18591 // configurable properties:
18592 // padding, isTarget, maintainOffset, primaryButtonOnly
18593 this.padding = this.config.padding || [0, 0, 0, 0];
18594 this.isTarget = (this.config.isTarget !== false);
18595 this.maintainOffset = (this.config.maintainOffset);
18596 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18601 * Executed when the linked element is available
18602 * @method handleOnAvailable
18605 handleOnAvailable: function() {
18606 this.available = true;
18607 this.resetConstraints();
18608 this.onAvailable();
18612 * Configures the padding for the target zone in px. Effectively expands
18613 * (or reduces) the virtual object size for targeting calculations.
18614 * Supports css-style shorthand; if only one parameter is passed, all sides
18615 * will have that padding, and if only two are passed, the top and bottom
18616 * will have the first param, the left and right the second.
18617 * @method setPadding
18618 * @param {int} iTop Top pad
18619 * @param {int} iRight Right pad
18620 * @param {int} iBot Bot pad
18621 * @param {int} iLeft Left pad
18623 setPadding: function(iTop, iRight, iBot, iLeft) {
18624 // this.padding = [iLeft, iRight, iTop, iBot];
18625 if (!iRight && 0 !== iRight) {
18626 this.padding = [iTop, iTop, iTop, iTop];
18627 } else if (!iBot && 0 !== iBot) {
18628 this.padding = [iTop, iRight, iTop, iRight];
18630 this.padding = [iTop, iRight, iBot, iLeft];
18635 * Stores the initial placement of the linked element.
18636 * @method setInitialPosition
18637 * @param {int} diffX the X offset, default 0
18638 * @param {int} diffY the Y offset, default 0
18640 setInitPosition: function(diffX, diffY) {
18641 var el = this.getEl();
18643 if (!this.DDM.verifyEl(el)) {
18647 var dx = diffX || 0;
18648 var dy = diffY || 0;
18650 var p = Dom.getXY( el );
18652 this.initPageX = p[0] - dx;
18653 this.initPageY = p[1] - dy;
18655 this.lastPageX = p[0];
18656 this.lastPageY = p[1];
18659 this.setStartPosition(p);
18663 * Sets the start position of the element. This is set when the obj
18664 * is initialized, the reset when a drag is started.
18665 * @method setStartPosition
18666 * @param pos current position (from previous lookup)
18669 setStartPosition: function(pos) {
18670 var p = pos || Dom.getXY( this.getEl() );
18671 this.deltaSetXY = null;
18673 this.startPageX = p[0];
18674 this.startPageY = p[1];
18678 * Add this instance to a group of related drag/drop objects. All
18679 * instances belong to at least one group, and can belong to as many
18680 * groups as needed.
18681 * @method addToGroup
18682 * @param sGroup {string} the name of the group
18684 addToGroup: function(sGroup) {
18685 this.groups[sGroup] = true;
18686 this.DDM.regDragDrop(this, sGroup);
18690 * Remove's this instance from the supplied interaction group
18691 * @method removeFromGroup
18692 * @param {string} sGroup The group to drop
18694 removeFromGroup: function(sGroup) {
18695 if (this.groups[sGroup]) {
18696 delete this.groups[sGroup];
18699 this.DDM.removeDDFromGroup(this, sGroup);
18703 * Allows you to specify that an element other than the linked element
18704 * will be moved with the cursor during a drag
18705 * @method setDragElId
18706 * @param id {string} the id of the element that will be used to initiate the drag
18708 setDragElId: function(id) {
18709 this.dragElId = id;
18713 * Allows you to specify a child of the linked element that should be
18714 * used to initiate the drag operation. An example of this would be if
18715 * you have a content div with text and links. Clicking anywhere in the
18716 * content area would normally start the drag operation. Use this method
18717 * to specify that an element inside of the content div is the element
18718 * that starts the drag operation.
18719 * @method setHandleElId
18720 * @param id {string} the id of the element that will be used to
18721 * initiate the drag.
18723 setHandleElId: function(id) {
18724 if (typeof id !== "string") {
18727 this.handleElId = id;
18728 this.DDM.regHandle(this.id, id);
18732 * Allows you to set an element outside of the linked element as a drag
18734 * @method setOuterHandleElId
18735 * @param id the id of the element that will be used to initiate the drag
18737 setOuterHandleElId: function(id) {
18738 if (typeof id !== "string") {
18741 Event.on(id, "mousedown",
18742 this.handleMouseDown, this);
18743 this.setHandleElId(id);
18745 this.hasOuterHandles = true;
18749 * Remove all drag and drop hooks for this element
18752 unreg: function() {
18753 Event.un(this.id, "mousedown",
18754 this.handleMouseDown);
18755 Event.un(this.id, "touchstart",
18756 this.handleMouseDown);
18757 this._domRef = null;
18758 this.DDM._remove(this);
18761 destroy : function(){
18766 * Returns true if this instance is locked, or the drag drop mgr is locked
18767 * (meaning that all drag/drop is disabled on the page.)
18769 * @return {boolean} true if this obj or all drag/drop is locked, else
18772 isLocked: function() {
18773 return (this.DDM.isLocked() || this.locked);
18777 * Fired when this object is clicked
18778 * @method handleMouseDown
18780 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18783 handleMouseDown: function(e, oDD){
18785 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18786 //Roo.log('not touch/ button !=0');
18789 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18790 return; // double touch..
18794 if (this.isLocked()) {
18795 //Roo.log('locked');
18799 this.DDM.refreshCache(this.groups);
18800 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18801 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18802 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18803 //Roo.log('no outer handes or not over target');
18806 // Roo.log('check validator');
18807 if (this.clickValidator(e)) {
18808 // Roo.log('validate success');
18809 // set the initial element position
18810 this.setStartPosition();
18813 this.b4MouseDown(e);
18814 this.onMouseDown(e);
18816 this.DDM.handleMouseDown(e, this);
18818 this.DDM.stopEvent(e);
18826 clickValidator: function(e) {
18827 var target = e.getTarget();
18828 return ( this.isValidHandleChild(target) &&
18829 (this.id == this.handleElId ||
18830 this.DDM.handleWasClicked(target, this.id)) );
18834 * Allows you to specify a tag name that should not start a drag operation
18835 * when clicked. This is designed to facilitate embedding links within a
18836 * drag handle that do something other than start the drag.
18837 * @method addInvalidHandleType
18838 * @param {string} tagName the type of element to exclude
18840 addInvalidHandleType: function(tagName) {
18841 var type = tagName.toUpperCase();
18842 this.invalidHandleTypes[type] = type;
18846 * Lets you to specify an element id for a child of a drag handle
18847 * that should not initiate a drag
18848 * @method addInvalidHandleId
18849 * @param {string} id the element id of the element you wish to ignore
18851 addInvalidHandleId: function(id) {
18852 if (typeof id !== "string") {
18855 this.invalidHandleIds[id] = id;
18859 * Lets you specify a css class of elements that will not initiate a drag
18860 * @method addInvalidHandleClass
18861 * @param {string} cssClass the class of the elements you wish to ignore
18863 addInvalidHandleClass: function(cssClass) {
18864 this.invalidHandleClasses.push(cssClass);
18868 * Unsets an excluded tag name set by addInvalidHandleType
18869 * @method removeInvalidHandleType
18870 * @param {string} tagName the type of element to unexclude
18872 removeInvalidHandleType: function(tagName) {
18873 var type = tagName.toUpperCase();
18874 // this.invalidHandleTypes[type] = null;
18875 delete this.invalidHandleTypes[type];
18879 * Unsets an invalid handle id
18880 * @method removeInvalidHandleId
18881 * @param {string} id the id of the element to re-enable
18883 removeInvalidHandleId: function(id) {
18884 if (typeof id !== "string") {
18887 delete this.invalidHandleIds[id];
18891 * Unsets an invalid css class
18892 * @method removeInvalidHandleClass
18893 * @param {string} cssClass the class of the element(s) you wish to
18896 removeInvalidHandleClass: function(cssClass) {
18897 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18898 if (this.invalidHandleClasses[i] == cssClass) {
18899 delete this.invalidHandleClasses[i];
18905 * Checks the tag exclusion list to see if this click should be ignored
18906 * @method isValidHandleChild
18907 * @param {HTMLElement} node the HTMLElement to evaluate
18908 * @return {boolean} true if this is a valid tag type, false if not
18910 isValidHandleChild: function(node) {
18913 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18916 nodeName = node.nodeName.toUpperCase();
18918 nodeName = node.nodeName;
18920 valid = valid && !this.invalidHandleTypes[nodeName];
18921 valid = valid && !this.invalidHandleIds[node.id];
18923 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18924 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18933 * Create the array of horizontal tick marks if an interval was specified
18934 * in setXConstraint().
18935 * @method setXTicks
18938 setXTicks: function(iStartX, iTickSize) {
18940 this.xTickSize = iTickSize;
18944 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18946 this.xTicks[this.xTicks.length] = i;
18951 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18953 this.xTicks[this.xTicks.length] = i;
18958 this.xTicks.sort(this.DDM.numericSort) ;
18962 * Create the array of vertical tick marks if an interval was specified in
18963 * setYConstraint().
18964 * @method setYTicks
18967 setYTicks: function(iStartY, iTickSize) {
18969 this.yTickSize = iTickSize;
18973 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18975 this.yTicks[this.yTicks.length] = i;
18980 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18982 this.yTicks[this.yTicks.length] = i;
18987 this.yTicks.sort(this.DDM.numericSort) ;
18991 * By default, the element can be dragged any place on the screen. Use
18992 * this method to limit the horizontal travel of the element. Pass in
18993 * 0,0 for the parameters if you want to lock the drag to the y axis.
18994 * @method setXConstraint
18995 * @param {int} iLeft the number of pixels the element can move to the left
18996 * @param {int} iRight the number of pixels the element can move to the
18998 * @param {int} iTickSize optional parameter for specifying that the
19000 * should move iTickSize pixels at a time.
19002 setXConstraint: function(iLeft, iRight, iTickSize) {
19003 this.leftConstraint = iLeft;
19004 this.rightConstraint = iRight;
19006 this.minX = this.initPageX - iLeft;
19007 this.maxX = this.initPageX + iRight;
19008 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19010 this.constrainX = true;
19014 * Clears any constraints applied to this instance. Also clears ticks
19015 * since they can't exist independent of a constraint at this time.
19016 * @method clearConstraints
19018 clearConstraints: function() {
19019 this.constrainX = false;
19020 this.constrainY = false;
19025 * Clears any tick interval defined for this instance
19026 * @method clearTicks
19028 clearTicks: function() {
19029 this.xTicks = null;
19030 this.yTicks = null;
19031 this.xTickSize = 0;
19032 this.yTickSize = 0;
19036 * By default, the element can be dragged any place on the screen. Set
19037 * this to limit the vertical travel of the element. Pass in 0,0 for the
19038 * parameters if you want to lock the drag to the x axis.
19039 * @method setYConstraint
19040 * @param {int} iUp the number of pixels the element can move up
19041 * @param {int} iDown the number of pixels the element can move down
19042 * @param {int} iTickSize optional parameter for specifying that the
19043 * element should move iTickSize pixels at a time.
19045 setYConstraint: function(iUp, iDown, iTickSize) {
19046 this.topConstraint = iUp;
19047 this.bottomConstraint = iDown;
19049 this.minY = this.initPageY - iUp;
19050 this.maxY = this.initPageY + iDown;
19051 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19053 this.constrainY = true;
19058 * resetConstraints must be called if you manually reposition a dd element.
19059 * @method resetConstraints
19060 * @param {boolean} maintainOffset
19062 resetConstraints: function() {
19065 // Maintain offsets if necessary
19066 if (this.initPageX || this.initPageX === 0) {
19067 // figure out how much this thing has moved
19068 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19069 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19071 this.setInitPosition(dx, dy);
19073 // This is the first time we have detected the element's position
19075 this.setInitPosition();
19078 if (this.constrainX) {
19079 this.setXConstraint( this.leftConstraint,
19080 this.rightConstraint,
19084 if (this.constrainY) {
19085 this.setYConstraint( this.topConstraint,
19086 this.bottomConstraint,
19092 * Normally the drag element is moved pixel by pixel, but we can specify
19093 * that it move a number of pixels at a time. This method resolves the
19094 * location when we have it set up like this.
19096 * @param {int} val where we want to place the object
19097 * @param {int[]} tickArray sorted array of valid points
19098 * @return {int} the closest tick
19101 getTick: function(val, tickArray) {
19104 // If tick interval is not defined, it is effectively 1 pixel,
19105 // so we return the value passed to us.
19107 } else if (tickArray[0] >= val) {
19108 // The value is lower than the first tick, so we return the first
19110 return tickArray[0];
19112 for (var i=0, len=tickArray.length; i<len; ++i) {
19114 if (tickArray[next] && tickArray[next] >= val) {
19115 var diff1 = val - tickArray[i];
19116 var diff2 = tickArray[next] - val;
19117 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19121 // The value is larger than the last tick, so we return the last
19123 return tickArray[tickArray.length - 1];
19130 * @return {string} string representation of the dd obj
19132 toString: function() {
19133 return ("DragDrop " + this.id);
19141 * Ext JS Library 1.1.1
19142 * Copyright(c) 2006-2007, Ext JS, LLC.
19144 * Originally Released Under LGPL - original licence link has changed is not relivant.
19147 * <script type="text/javascript">
19152 * The drag and drop utility provides a framework for building drag and drop
19153 * applications. In addition to enabling drag and drop for specific elements,
19154 * the drag and drop elements are tracked by the manager class, and the
19155 * interactions between the various elements are tracked during the drag and
19156 * the implementing code is notified about these important moments.
19159 // Only load the library once. Rewriting the manager class would orphan
19160 // existing drag and drop instances.
19161 if (!Roo.dd.DragDropMgr) {
19164 * @class Roo.dd.DragDropMgr
19165 * DragDropMgr is a singleton that tracks the element interaction for
19166 * all DragDrop items in the window. Generally, you will not call
19167 * this class directly, but it does have helper methods that could
19168 * be useful in your DragDrop implementations.
19171 Roo.dd.DragDropMgr = function() {
19173 var Event = Roo.EventManager;
19178 * Two dimensional Array of registered DragDrop objects. The first
19179 * dimension is the DragDrop item group, the second the DragDrop
19182 * @type {string: string}
19189 * Array of element ids defined as drag handles. Used to determine
19190 * if the element that generated the mousedown event is actually the
19191 * handle and not the html element itself.
19192 * @property handleIds
19193 * @type {string: string}
19200 * the DragDrop object that is currently being dragged
19201 * @property dragCurrent
19209 * the DragDrop object(s) that are being hovered over
19210 * @property dragOvers
19218 * the X distance between the cursor and the object being dragged
19227 * the Y distance between the cursor and the object being dragged
19236 * Flag to determine if we should prevent the default behavior of the
19237 * events we define. By default this is true, but this can be set to
19238 * false if you need the default behavior (not recommended)
19239 * @property preventDefault
19243 preventDefault: true,
19246 * Flag to determine if we should stop the propagation of the events
19247 * we generate. This is true by default but you may want to set it to
19248 * false if the html element contains other features that require the
19250 * @property stopPropagation
19254 stopPropagation: true,
19257 * Internal flag that is set to true when drag and drop has been
19259 * @property initialized
19266 * All drag and drop can be disabled.
19274 * Called the first time an element is registered.
19280 this.initialized = true;
19284 * In point mode, drag and drop interaction is defined by the
19285 * location of the cursor during the drag/drop
19293 * In intersect mode, drag and drop interactio nis defined by the
19294 * overlap of two or more drag and drop objects.
19295 * @property INTERSECT
19302 * The current drag and drop mode. Default: POINT
19310 * Runs method on all drag and drop objects
19311 * @method _execOnAll
19315 _execOnAll: function(sMethod, args) {
19316 for (var i in this.ids) {
19317 for (var j in this.ids[i]) {
19318 var oDD = this.ids[i][j];
19319 if (! this.isTypeOfDD(oDD)) {
19322 oDD[sMethod].apply(oDD, args);
19328 * Drag and drop initialization. Sets up the global event handlers
19333 _onLoad: function() {
19337 if (!Roo.isTouch) {
19338 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19339 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19341 Event.on(document, "touchend", this.handleMouseUp, this, true);
19342 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19344 Event.on(window, "unload", this._onUnload, this, true);
19345 Event.on(window, "resize", this._onResize, this, true);
19346 // Event.on(window, "mouseout", this._test);
19351 * Reset constraints on all drag and drop objs
19352 * @method _onResize
19356 _onResize: function(e) {
19357 this._execOnAll("resetConstraints", []);
19361 * Lock all drag and drop functionality
19365 lock: function() { this.locked = true; },
19368 * Unlock all drag and drop functionality
19372 unlock: function() { this.locked = false; },
19375 * Is drag and drop locked?
19377 * @return {boolean} True if drag and drop is locked, false otherwise.
19380 isLocked: function() { return this.locked; },
19383 * Location cache that is set for all drag drop objects when a drag is
19384 * initiated, cleared when the drag is finished.
19385 * @property locationCache
19392 * Set useCache to false if you want to force object the lookup of each
19393 * drag and drop linked element constantly during a drag.
19394 * @property useCache
19401 * The number of pixels that the mouse needs to move after the
19402 * mousedown before the drag is initiated. Default=3;
19403 * @property clickPixelThresh
19407 clickPixelThresh: 3,
19410 * The number of milliseconds after the mousedown event to initiate the
19411 * drag if we don't get a mouseup event. Default=1000
19412 * @property clickTimeThresh
19416 clickTimeThresh: 350,
19419 * Flag that indicates that either the drag pixel threshold or the
19420 * mousdown time threshold has been met
19421 * @property dragThreshMet
19426 dragThreshMet: false,
19429 * Timeout used for the click time threshold
19430 * @property clickTimeout
19435 clickTimeout: null,
19438 * The X position of the mousedown event stored for later use when a
19439 * drag threshold is met.
19448 * The Y position of the mousedown event stored for later use when a
19449 * drag threshold is met.
19458 * Each DragDrop instance must be registered with the DragDropMgr.
19459 * This is executed in DragDrop.init()
19460 * @method regDragDrop
19461 * @param {DragDrop} oDD the DragDrop object to register
19462 * @param {String} sGroup the name of the group this element belongs to
19465 regDragDrop: function(oDD, sGroup) {
19466 if (!this.initialized) { this.init(); }
19468 if (!this.ids[sGroup]) {
19469 this.ids[sGroup] = {};
19471 this.ids[sGroup][oDD.id] = oDD;
19475 * Removes the supplied dd instance from the supplied group. Executed
19476 * by DragDrop.removeFromGroup, so don't call this function directly.
19477 * @method removeDDFromGroup
19481 removeDDFromGroup: function(oDD, sGroup) {
19482 if (!this.ids[sGroup]) {
19483 this.ids[sGroup] = {};
19486 var obj = this.ids[sGroup];
19487 if (obj && obj[oDD.id]) {
19488 delete obj[oDD.id];
19493 * Unregisters a drag and drop item. This is executed in
19494 * DragDrop.unreg, use that method instead of calling this directly.
19499 _remove: function(oDD) {
19500 for (var g in oDD.groups) {
19501 if (g && this.ids[g][oDD.id]) {
19502 delete this.ids[g][oDD.id];
19505 delete this.handleIds[oDD.id];
19509 * Each DragDrop handle element must be registered. This is done
19510 * automatically when executing DragDrop.setHandleElId()
19511 * @method regHandle
19512 * @param {String} sDDId the DragDrop id this element is a handle for
19513 * @param {String} sHandleId the id of the element that is the drag
19517 regHandle: function(sDDId, sHandleId) {
19518 if (!this.handleIds[sDDId]) {
19519 this.handleIds[sDDId] = {};
19521 this.handleIds[sDDId][sHandleId] = sHandleId;
19525 * Utility function to determine if a given element has been
19526 * registered as a drag drop item.
19527 * @method isDragDrop
19528 * @param {String} id the element id to check
19529 * @return {boolean} true if this element is a DragDrop item,
19533 isDragDrop: function(id) {
19534 return ( this.getDDById(id) ) ? true : false;
19538 * Returns the drag and drop instances that are in all groups the
19539 * passed in instance belongs to.
19540 * @method getRelated
19541 * @param {DragDrop} p_oDD the obj to get related data for
19542 * @param {boolean} bTargetsOnly if true, only return targetable objs
19543 * @return {DragDrop[]} the related instances
19546 getRelated: function(p_oDD, bTargetsOnly) {
19548 for (var i in p_oDD.groups) {
19549 for (j in this.ids[i]) {
19550 var dd = this.ids[i][j];
19551 if (! this.isTypeOfDD(dd)) {
19554 if (!bTargetsOnly || dd.isTarget) {
19555 oDDs[oDDs.length] = dd;
19564 * Returns true if the specified dd target is a legal target for
19565 * the specifice drag obj
19566 * @method isLegalTarget
19567 * @param {DragDrop} the drag obj
19568 * @param {DragDrop} the target
19569 * @return {boolean} true if the target is a legal target for the
19573 isLegalTarget: function (oDD, oTargetDD) {
19574 var targets = this.getRelated(oDD, true);
19575 for (var i=0, len=targets.length;i<len;++i) {
19576 if (targets[i].id == oTargetDD.id) {
19585 * My goal is to be able to transparently determine if an object is
19586 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19587 * returns "object", oDD.constructor.toString() always returns
19588 * "DragDrop" and not the name of the subclass. So for now it just
19589 * evaluates a well-known variable in DragDrop.
19590 * @method isTypeOfDD
19591 * @param {Object} the object to evaluate
19592 * @return {boolean} true if typeof oDD = DragDrop
19595 isTypeOfDD: function (oDD) {
19596 return (oDD && oDD.__ygDragDrop);
19600 * Utility function to determine if a given element has been
19601 * registered as a drag drop handle for the given Drag Drop object.
19603 * @param {String} id the element id to check
19604 * @return {boolean} true if this element is a DragDrop handle, false
19608 isHandle: function(sDDId, sHandleId) {
19609 return ( this.handleIds[sDDId] &&
19610 this.handleIds[sDDId][sHandleId] );
19614 * Returns the DragDrop instance for a given id
19615 * @method getDDById
19616 * @param {String} id the id of the DragDrop object
19617 * @return {DragDrop} the drag drop object, null if it is not found
19620 getDDById: function(id) {
19621 for (var i in this.ids) {
19622 if (this.ids[i][id]) {
19623 return this.ids[i][id];
19630 * Fired after a registered DragDrop object gets the mousedown event.
19631 * Sets up the events required to track the object being dragged
19632 * @method handleMouseDown
19633 * @param {Event} e the event
19634 * @param oDD the DragDrop object being dragged
19638 handleMouseDown: function(e, oDD) {
19640 Roo.QuickTips.disable();
19642 this.currentTarget = e.getTarget();
19644 this.dragCurrent = oDD;
19646 var el = oDD.getEl();
19648 // track start position
19649 this.startX = e.getPageX();
19650 this.startY = e.getPageY();
19652 this.deltaX = this.startX - el.offsetLeft;
19653 this.deltaY = this.startY - el.offsetTop;
19655 this.dragThreshMet = false;
19657 this.clickTimeout = setTimeout(
19659 var DDM = Roo.dd.DDM;
19660 DDM.startDrag(DDM.startX, DDM.startY);
19662 this.clickTimeThresh );
19666 * Fired when either the drag pixel threshol or the mousedown hold
19667 * time threshold has been met.
19668 * @method startDrag
19669 * @param x {int} the X position of the original mousedown
19670 * @param y {int} the Y position of the original mousedown
19673 startDrag: function(x, y) {
19674 clearTimeout(this.clickTimeout);
19675 if (this.dragCurrent) {
19676 this.dragCurrent.b4StartDrag(x, y);
19677 this.dragCurrent.startDrag(x, y);
19679 this.dragThreshMet = true;
19683 * Internal function to handle the mouseup event. Will be invoked
19684 * from the context of the document.
19685 * @method handleMouseUp
19686 * @param {Event} e the event
19690 handleMouseUp: function(e) {
19693 Roo.QuickTips.enable();
19695 if (! this.dragCurrent) {
19699 clearTimeout(this.clickTimeout);
19701 if (this.dragThreshMet) {
19702 this.fireEvents(e, true);
19712 * Utility to stop event propagation and event default, if these
19713 * features are turned on.
19714 * @method stopEvent
19715 * @param {Event} e the event as returned by this.getEvent()
19718 stopEvent: function(e){
19719 if(this.stopPropagation) {
19720 e.stopPropagation();
19723 if (this.preventDefault) {
19724 e.preventDefault();
19729 * Internal function to clean up event handlers after the drag
19730 * operation is complete
19732 * @param {Event} e the event
19736 stopDrag: function(e) {
19737 // Fire the drag end event for the item that was dragged
19738 if (this.dragCurrent) {
19739 if (this.dragThreshMet) {
19740 this.dragCurrent.b4EndDrag(e);
19741 this.dragCurrent.endDrag(e);
19744 this.dragCurrent.onMouseUp(e);
19747 this.dragCurrent = null;
19748 this.dragOvers = {};
19752 * Internal function to handle the mousemove event. Will be invoked
19753 * from the context of the html element.
19755 * @TODO figure out what we can do about mouse events lost when the
19756 * user drags objects beyond the window boundary. Currently we can
19757 * detect this in internet explorer by verifying that the mouse is
19758 * down during the mousemove event. Firefox doesn't give us the
19759 * button state on the mousemove event.
19760 * @method handleMouseMove
19761 * @param {Event} e the event
19765 handleMouseMove: function(e) {
19766 if (! this.dragCurrent) {
19770 // var button = e.which || e.button;
19772 // check for IE mouseup outside of page boundary
19773 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19775 return this.handleMouseUp(e);
19778 if (!this.dragThreshMet) {
19779 var diffX = Math.abs(this.startX - e.getPageX());
19780 var diffY = Math.abs(this.startY - e.getPageY());
19781 if (diffX > this.clickPixelThresh ||
19782 diffY > this.clickPixelThresh) {
19783 this.startDrag(this.startX, this.startY);
19787 if (this.dragThreshMet) {
19788 this.dragCurrent.b4Drag(e);
19789 this.dragCurrent.onDrag(e);
19790 if(!this.dragCurrent.moveOnly){
19791 this.fireEvents(e, false);
19801 * Iterates over all of the DragDrop elements to find ones we are
19802 * hovering over or dropping on
19803 * @method fireEvents
19804 * @param {Event} e the event
19805 * @param {boolean} isDrop is this a drop op or a mouseover op?
19809 fireEvents: function(e, isDrop) {
19810 var dc = this.dragCurrent;
19812 // If the user did the mouse up outside of the window, we could
19813 // get here even though we have ended the drag.
19814 if (!dc || dc.isLocked()) {
19818 var pt = e.getPoint();
19820 // cache the previous dragOver array
19826 var enterEvts = [];
19828 // Check to see if the object(s) we were hovering over is no longer
19829 // being hovered over so we can fire the onDragOut event
19830 for (var i in this.dragOvers) {
19832 var ddo = this.dragOvers[i];
19834 if (! this.isTypeOfDD(ddo)) {
19838 if (! this.isOverTarget(pt, ddo, this.mode)) {
19839 outEvts.push( ddo );
19842 oldOvers[i] = true;
19843 delete this.dragOvers[i];
19846 for (var sGroup in dc.groups) {
19848 if ("string" != typeof sGroup) {
19852 for (i in this.ids[sGroup]) {
19853 var oDD = this.ids[sGroup][i];
19854 if (! this.isTypeOfDD(oDD)) {
19858 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19859 if (this.isOverTarget(pt, oDD, this.mode)) {
19860 // look for drop interactions
19862 dropEvts.push( oDD );
19863 // look for drag enter and drag over interactions
19866 // initial drag over: dragEnter fires
19867 if (!oldOvers[oDD.id]) {
19868 enterEvts.push( oDD );
19869 // subsequent drag overs: dragOver fires
19871 overEvts.push( oDD );
19874 this.dragOvers[oDD.id] = oDD;
19882 if (outEvts.length) {
19883 dc.b4DragOut(e, outEvts);
19884 dc.onDragOut(e, outEvts);
19887 if (enterEvts.length) {
19888 dc.onDragEnter(e, enterEvts);
19891 if (overEvts.length) {
19892 dc.b4DragOver(e, overEvts);
19893 dc.onDragOver(e, overEvts);
19896 if (dropEvts.length) {
19897 dc.b4DragDrop(e, dropEvts);
19898 dc.onDragDrop(e, dropEvts);
19902 // fire dragout events
19904 for (i=0, len=outEvts.length; i<len; ++i) {
19905 dc.b4DragOut(e, outEvts[i].id);
19906 dc.onDragOut(e, outEvts[i].id);
19909 // fire enter events
19910 for (i=0,len=enterEvts.length; i<len; ++i) {
19911 // dc.b4DragEnter(e, oDD.id);
19912 dc.onDragEnter(e, enterEvts[i].id);
19915 // fire over events
19916 for (i=0,len=overEvts.length; i<len; ++i) {
19917 dc.b4DragOver(e, overEvts[i].id);
19918 dc.onDragOver(e, overEvts[i].id);
19921 // fire drop events
19922 for (i=0, len=dropEvts.length; i<len; ++i) {
19923 dc.b4DragDrop(e, dropEvts[i].id);
19924 dc.onDragDrop(e, dropEvts[i].id);
19929 // notify about a drop that did not find a target
19930 if (isDrop && !dropEvts.length) {
19931 dc.onInvalidDrop(e);
19937 * Helper function for getting the best match from the list of drag
19938 * and drop objects returned by the drag and drop events when we are
19939 * in INTERSECT mode. It returns either the first object that the
19940 * cursor is over, or the object that has the greatest overlap with
19941 * the dragged element.
19942 * @method getBestMatch
19943 * @param {DragDrop[]} dds The array of drag and drop objects
19945 * @return {DragDrop} The best single match
19948 getBestMatch: function(dds) {
19950 // Return null if the input is not what we expect
19951 //if (!dds || !dds.length || dds.length == 0) {
19953 // If there is only one item, it wins
19954 //} else if (dds.length == 1) {
19956 var len = dds.length;
19961 // Loop through the targeted items
19962 for (var i=0; i<len; ++i) {
19964 // If the cursor is over the object, it wins. If the
19965 // cursor is over multiple matches, the first one we come
19967 if (dd.cursorIsOver) {
19970 // Otherwise the object with the most overlap wins
19973 winner.overlap.getArea() < dd.overlap.getArea()) {
19984 * Refreshes the cache of the top-left and bottom-right points of the
19985 * drag and drop objects in the specified group(s). This is in the
19986 * format that is stored in the drag and drop instance, so typical
19989 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19993 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19995 * @TODO this really should be an indexed array. Alternatively this
19996 * method could accept both.
19997 * @method refreshCache
19998 * @param {Object} groups an associative array of groups to refresh
20001 refreshCache: function(groups) {
20002 for (var sGroup in groups) {
20003 if ("string" != typeof sGroup) {
20006 for (var i in this.ids[sGroup]) {
20007 var oDD = this.ids[sGroup][i];
20009 if (this.isTypeOfDD(oDD)) {
20010 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20011 var loc = this.getLocation(oDD);
20013 this.locationCache[oDD.id] = loc;
20015 delete this.locationCache[oDD.id];
20016 // this will unregister the drag and drop object if
20017 // the element is not in a usable state
20026 * This checks to make sure an element exists and is in the DOM. The
20027 * main purpose is to handle cases where innerHTML is used to remove
20028 * drag and drop objects from the DOM. IE provides an 'unspecified
20029 * error' when trying to access the offsetParent of such an element
20031 * @param {HTMLElement} el the element to check
20032 * @return {boolean} true if the element looks usable
20035 verifyEl: function(el) {
20040 parent = el.offsetParent;
20043 parent = el.offsetParent;
20054 * Returns a Region object containing the drag and drop element's position
20055 * and size, including the padding configured for it
20056 * @method getLocation
20057 * @param {DragDrop} oDD the drag and drop object to get the
20059 * @return {Roo.lib.Region} a Region object representing the total area
20060 * the element occupies, including any padding
20061 * the instance is configured for.
20064 getLocation: function(oDD) {
20065 if (! this.isTypeOfDD(oDD)) {
20069 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20072 pos= Roo.lib.Dom.getXY(el);
20080 x2 = x1 + el.offsetWidth;
20082 y2 = y1 + el.offsetHeight;
20084 t = y1 - oDD.padding[0];
20085 r = x2 + oDD.padding[1];
20086 b = y2 + oDD.padding[2];
20087 l = x1 - oDD.padding[3];
20089 return new Roo.lib.Region( t, r, b, l );
20093 * Checks the cursor location to see if it over the target
20094 * @method isOverTarget
20095 * @param {Roo.lib.Point} pt The point to evaluate
20096 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20097 * @return {boolean} true if the mouse is over the target
20101 isOverTarget: function(pt, oTarget, intersect) {
20102 // use cache if available
20103 var loc = this.locationCache[oTarget.id];
20104 if (!loc || !this.useCache) {
20105 loc = this.getLocation(oTarget);
20106 this.locationCache[oTarget.id] = loc;
20114 oTarget.cursorIsOver = loc.contains( pt );
20116 // DragDrop is using this as a sanity check for the initial mousedown
20117 // in this case we are done. In POINT mode, if the drag obj has no
20118 // contraints, we are also done. Otherwise we need to evaluate the
20119 // location of the target as related to the actual location of the
20120 // dragged element.
20121 var dc = this.dragCurrent;
20122 if (!dc || !dc.getTargetCoord ||
20123 (!intersect && !dc.constrainX && !dc.constrainY)) {
20124 return oTarget.cursorIsOver;
20127 oTarget.overlap = null;
20129 // Get the current location of the drag element, this is the
20130 // location of the mouse event less the delta that represents
20131 // where the original mousedown happened on the element. We
20132 // need to consider constraints and ticks as well.
20133 var pos = dc.getTargetCoord(pt.x, pt.y);
20135 var el = dc.getDragEl();
20136 var curRegion = new Roo.lib.Region( pos.y,
20137 pos.x + el.offsetWidth,
20138 pos.y + el.offsetHeight,
20141 var overlap = curRegion.intersect(loc);
20144 oTarget.overlap = overlap;
20145 return (intersect) ? true : oTarget.cursorIsOver;
20152 * unload event handler
20153 * @method _onUnload
20157 _onUnload: function(e, me) {
20158 Roo.dd.DragDropMgr.unregAll();
20162 * Cleans up the drag and drop events and objects.
20167 unregAll: function() {
20169 if (this.dragCurrent) {
20171 this.dragCurrent = null;
20174 this._execOnAll("unreg", []);
20176 for (i in this.elementCache) {
20177 delete this.elementCache[i];
20180 this.elementCache = {};
20185 * A cache of DOM elements
20186 * @property elementCache
20193 * Get the wrapper for the DOM element specified
20194 * @method getElWrapper
20195 * @param {String} id the id of the element to get
20196 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20198 * @deprecated This wrapper isn't that useful
20201 getElWrapper: function(id) {
20202 var oWrapper = this.elementCache[id];
20203 if (!oWrapper || !oWrapper.el) {
20204 oWrapper = this.elementCache[id] =
20205 new this.ElementWrapper(Roo.getDom(id));
20211 * Returns the actual DOM element
20212 * @method getElement
20213 * @param {String} id the id of the elment to get
20214 * @return {Object} The element
20215 * @deprecated use Roo.getDom instead
20218 getElement: function(id) {
20219 return Roo.getDom(id);
20223 * Returns the style property for the DOM element (i.e.,
20224 * document.getElById(id).style)
20226 * @param {String} id the id of the elment to get
20227 * @return {Object} The style property of the element
20228 * @deprecated use Roo.getDom instead
20231 getCss: function(id) {
20232 var el = Roo.getDom(id);
20233 return (el) ? el.style : null;
20237 * Inner class for cached elements
20238 * @class DragDropMgr.ElementWrapper
20243 ElementWrapper: function(el) {
20248 this.el = el || null;
20253 this.id = this.el && el.id;
20255 * A reference to the style property
20258 this.css = this.el && el.style;
20262 * Returns the X position of an html element
20264 * @param el the element for which to get the position
20265 * @return {int} the X coordinate
20267 * @deprecated use Roo.lib.Dom.getX instead
20270 getPosX: function(el) {
20271 return Roo.lib.Dom.getX(el);
20275 * Returns the Y position of an html element
20277 * @param el the element for which to get the position
20278 * @return {int} the Y coordinate
20279 * @deprecated use Roo.lib.Dom.getY instead
20282 getPosY: function(el) {
20283 return Roo.lib.Dom.getY(el);
20287 * Swap two nodes. In IE, we use the native method, for others we
20288 * emulate the IE behavior
20290 * @param n1 the first node to swap
20291 * @param n2 the other node to swap
20294 swapNode: function(n1, n2) {
20298 var p = n2.parentNode;
20299 var s = n2.nextSibling;
20302 p.insertBefore(n1, n2);
20303 } else if (n2 == n1.nextSibling) {
20304 p.insertBefore(n2, n1);
20306 n1.parentNode.replaceChild(n2, n1);
20307 p.insertBefore(n1, s);
20313 * Returns the current scroll position
20314 * @method getScroll
20318 getScroll: function () {
20319 var t, l, dde=document.documentElement, db=document.body;
20320 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20322 l = dde.scrollLeft;
20329 return { top: t, left: l };
20333 * Returns the specified element style property
20335 * @param {HTMLElement} el the element
20336 * @param {string} styleProp the style property
20337 * @return {string} The value of the style property
20338 * @deprecated use Roo.lib.Dom.getStyle
20341 getStyle: function(el, styleProp) {
20342 return Roo.fly(el).getStyle(styleProp);
20346 * Gets the scrollTop
20347 * @method getScrollTop
20348 * @return {int} the document's scrollTop
20351 getScrollTop: function () { return this.getScroll().top; },
20354 * Gets the scrollLeft
20355 * @method getScrollLeft
20356 * @return {int} the document's scrollTop
20359 getScrollLeft: function () { return this.getScroll().left; },
20362 * Sets the x/y position of an element to the location of the
20365 * @param {HTMLElement} moveEl The element to move
20366 * @param {HTMLElement} targetEl The position reference element
20369 moveToEl: function (moveEl, targetEl) {
20370 var aCoord = Roo.lib.Dom.getXY(targetEl);
20371 Roo.lib.Dom.setXY(moveEl, aCoord);
20375 * Numeric array sort function
20376 * @method numericSort
20379 numericSort: function(a, b) { return (a - b); },
20383 * @property _timeoutCount
20390 * Trying to make the load order less important. Without this we get
20391 * an error if this file is loaded before the Event Utility.
20392 * @method _addListeners
20396 _addListeners: function() {
20397 var DDM = Roo.dd.DDM;
20398 if ( Roo.lib.Event && document ) {
20401 if (DDM._timeoutCount > 2000) {
20403 setTimeout(DDM._addListeners, 10);
20404 if (document && document.body) {
20405 DDM._timeoutCount += 1;
20412 * Recursively searches the immediate parent and all child nodes for
20413 * the handle element in order to determine wheter or not it was
20415 * @method handleWasClicked
20416 * @param node the html element to inspect
20419 handleWasClicked: function(node, id) {
20420 if (this.isHandle(id, node.id)) {
20423 // check to see if this is a text node child of the one we want
20424 var p = node.parentNode;
20427 if (this.isHandle(id, p.id)) {
20442 // shorter alias, save a few bytes
20443 Roo.dd.DDM = Roo.dd.DragDropMgr;
20444 Roo.dd.DDM._addListeners();
20448 * Ext JS Library 1.1.1
20449 * Copyright(c) 2006-2007, Ext JS, LLC.
20451 * Originally Released Under LGPL - original licence link has changed is not relivant.
20454 * <script type="text/javascript">
20459 * A DragDrop implementation where the linked element follows the
20460 * mouse cursor during a drag.
20461 * @extends Roo.dd.DragDrop
20463 * @param {String} id the id of the linked element
20464 * @param {String} sGroup the group of related DragDrop items
20465 * @param {object} config an object containing configurable attributes
20466 * Valid properties for DD:
20469 Roo.dd.DD = function(id, sGroup, config) {
20471 this.init(id, sGroup, config);
20475 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20478 * When set to true, the utility automatically tries to scroll the browser
20479 * window wehn a drag and drop element is dragged near the viewport boundary.
20480 * Defaults to true.
20487 * Sets the pointer offset to the distance between the linked element's top
20488 * left corner and the location the element was clicked
20489 * @method autoOffset
20490 * @param {int} iPageX the X coordinate of the click
20491 * @param {int} iPageY the Y coordinate of the click
20493 autoOffset: function(iPageX, iPageY) {
20494 var x = iPageX - this.startPageX;
20495 var y = iPageY - this.startPageY;
20496 this.setDelta(x, y);
20500 * Sets the pointer offset. You can call this directly to force the
20501 * offset to be in a particular location (e.g., pass in 0,0 to set it
20502 * to the center of the object)
20504 * @param {int} iDeltaX the distance from the left
20505 * @param {int} iDeltaY the distance from the top
20507 setDelta: function(iDeltaX, iDeltaY) {
20508 this.deltaX = iDeltaX;
20509 this.deltaY = iDeltaY;
20513 * Sets the drag element to the location of the mousedown or click event,
20514 * maintaining the cursor location relative to the location on the element
20515 * that was clicked. Override this if you want to place the element in a
20516 * location other than where the cursor is.
20517 * @method setDragElPos
20518 * @param {int} iPageX the X coordinate of the mousedown or drag event
20519 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20521 setDragElPos: function(iPageX, iPageY) {
20522 // the first time we do this, we are going to check to make sure
20523 // the element has css positioning
20525 var el = this.getDragEl();
20526 this.alignElWithMouse(el, iPageX, iPageY);
20530 * Sets the element to the location of the mousedown or click event,
20531 * maintaining the cursor location relative to the location on the element
20532 * that was clicked. Override this if you want to place the element in a
20533 * location other than where the cursor is.
20534 * @method alignElWithMouse
20535 * @param {HTMLElement} el the element to move
20536 * @param {int} iPageX the X coordinate of the mousedown or drag event
20537 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20539 alignElWithMouse: function(el, iPageX, iPageY) {
20540 var oCoord = this.getTargetCoord(iPageX, iPageY);
20541 var fly = el.dom ? el : Roo.fly(el);
20542 if (!this.deltaSetXY) {
20543 var aCoord = [oCoord.x, oCoord.y];
20545 var newLeft = fly.getLeft(true);
20546 var newTop = fly.getTop(true);
20547 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20549 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20552 this.cachePosition(oCoord.x, oCoord.y);
20553 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20558 * Saves the most recent position so that we can reset the constraints and
20559 * tick marks on-demand. We need to know this so that we can calculate the
20560 * number of pixels the element is offset from its original position.
20561 * @method cachePosition
20562 * @param iPageX the current x position (optional, this just makes it so we
20563 * don't have to look it up again)
20564 * @param iPageY the current y position (optional, this just makes it so we
20565 * don't have to look it up again)
20567 cachePosition: function(iPageX, iPageY) {
20569 this.lastPageX = iPageX;
20570 this.lastPageY = iPageY;
20572 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20573 this.lastPageX = aCoord[0];
20574 this.lastPageY = aCoord[1];
20579 * Auto-scroll the window if the dragged object has been moved beyond the
20580 * visible window boundary.
20581 * @method autoScroll
20582 * @param {int} x the drag element's x position
20583 * @param {int} y the drag element's y position
20584 * @param {int} h the height of the drag element
20585 * @param {int} w the width of the drag element
20588 autoScroll: function(x, y, h, w) {
20591 // The client height
20592 var clientH = Roo.lib.Dom.getViewWidth();
20594 // The client width
20595 var clientW = Roo.lib.Dom.getViewHeight();
20597 // The amt scrolled down
20598 var st = this.DDM.getScrollTop();
20600 // The amt scrolled right
20601 var sl = this.DDM.getScrollLeft();
20603 // Location of the bottom of the element
20606 // Location of the right of the element
20609 // The distance from the cursor to the bottom of the visible area,
20610 // adjusted so that we don't scroll if the cursor is beyond the
20611 // element drag constraints
20612 var toBot = (clientH + st - y - this.deltaY);
20614 // The distance from the cursor to the right of the visible area
20615 var toRight = (clientW + sl - x - this.deltaX);
20618 // How close to the edge the cursor must be before we scroll
20619 // var thresh = (document.all) ? 100 : 40;
20622 // How many pixels to scroll per autoscroll op. This helps to reduce
20623 // clunky scrolling. IE is more sensitive about this ... it needs this
20624 // value to be higher.
20625 var scrAmt = (document.all) ? 80 : 30;
20627 // Scroll down if we are near the bottom of the visible page and the
20628 // obj extends below the crease
20629 if ( bot > clientH && toBot < thresh ) {
20630 window.scrollTo(sl, st + scrAmt);
20633 // Scroll up if the window is scrolled down and the top of the object
20634 // goes above the top border
20635 if ( y < st && st > 0 && y - st < thresh ) {
20636 window.scrollTo(sl, st - scrAmt);
20639 // Scroll right if the obj is beyond the right border and the cursor is
20640 // near the border.
20641 if ( right > clientW && toRight < thresh ) {
20642 window.scrollTo(sl + scrAmt, st);
20645 // Scroll left if the window has been scrolled to the right and the obj
20646 // extends past the left border
20647 if ( x < sl && sl > 0 && x - sl < thresh ) {
20648 window.scrollTo(sl - scrAmt, st);
20654 * Finds the location the element should be placed if we want to move
20655 * it to where the mouse location less the click offset would place us.
20656 * @method getTargetCoord
20657 * @param {int} iPageX the X coordinate of the click
20658 * @param {int} iPageY the Y coordinate of the click
20659 * @return an object that contains the coordinates (Object.x and Object.y)
20662 getTargetCoord: function(iPageX, iPageY) {
20665 var x = iPageX - this.deltaX;
20666 var y = iPageY - this.deltaY;
20668 if (this.constrainX) {
20669 if (x < this.minX) { x = this.minX; }
20670 if (x > this.maxX) { x = this.maxX; }
20673 if (this.constrainY) {
20674 if (y < this.minY) { y = this.minY; }
20675 if (y > this.maxY) { y = this.maxY; }
20678 x = this.getTick(x, this.xTicks);
20679 y = this.getTick(y, this.yTicks);
20686 * Sets up config options specific to this class. Overrides
20687 * Roo.dd.DragDrop, but all versions of this method through the
20688 * inheritance chain are called
20690 applyConfig: function() {
20691 Roo.dd.DD.superclass.applyConfig.call(this);
20692 this.scroll = (this.config.scroll !== false);
20696 * Event that fires prior to the onMouseDown event. Overrides
20699 b4MouseDown: function(e) {
20700 // this.resetConstraints();
20701 this.autoOffset(e.getPageX(),
20706 * Event that fires prior to the onDrag event. Overrides
20709 b4Drag: function(e) {
20710 this.setDragElPos(e.getPageX(),
20714 toString: function() {
20715 return ("DD " + this.id);
20718 //////////////////////////////////////////////////////////////////////////
20719 // Debugging ygDragDrop events that can be overridden
20720 //////////////////////////////////////////////////////////////////////////
20722 startDrag: function(x, y) {
20725 onDrag: function(e) {
20728 onDragEnter: function(e, id) {
20731 onDragOver: function(e, id) {
20734 onDragOut: function(e, id) {
20737 onDragDrop: function(e, id) {
20740 endDrag: function(e) {
20747 * Ext JS Library 1.1.1
20748 * Copyright(c) 2006-2007, Ext JS, LLC.
20750 * Originally Released Under LGPL - original licence link has changed is not relivant.
20753 * <script type="text/javascript">
20757 * @class Roo.dd.DDProxy
20758 * A DragDrop implementation that inserts an empty, bordered div into
20759 * the document that follows the cursor during drag operations. At the time of
20760 * the click, the frame div is resized to the dimensions of the linked html
20761 * element, and moved to the exact location of the linked element.
20763 * References to the "frame" element refer to the single proxy element that
20764 * was created to be dragged in place of all DDProxy elements on the
20767 * @extends Roo.dd.DD
20769 * @param {String} id the id of the linked html element
20770 * @param {String} sGroup the group of related DragDrop objects
20771 * @param {object} config an object containing configurable attributes
20772 * Valid properties for DDProxy in addition to those in DragDrop:
20773 * resizeFrame, centerFrame, dragElId
20775 Roo.dd.DDProxy = function(id, sGroup, config) {
20777 this.init(id, sGroup, config);
20783 * The default drag frame div id
20784 * @property Roo.dd.DDProxy.dragElId
20788 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20790 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20793 * By default we resize the drag frame to be the same size as the element
20794 * we want to drag (this is to get the frame effect). We can turn it off
20795 * if we want a different behavior.
20796 * @property resizeFrame
20802 * By default the frame is positioned exactly where the drag element is, so
20803 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20804 * you do not have constraints on the obj is to have the drag frame centered
20805 * around the cursor. Set centerFrame to true for this effect.
20806 * @property centerFrame
20809 centerFrame: false,
20812 * Creates the proxy element if it does not yet exist
20813 * @method createFrame
20815 createFrame: function() {
20817 var body = document.body;
20819 if (!body || !body.firstChild) {
20820 setTimeout( function() { self.createFrame(); }, 50 );
20824 var div = this.getDragEl();
20827 div = document.createElement("div");
20828 div.id = this.dragElId;
20831 s.position = "absolute";
20832 s.visibility = "hidden";
20834 s.border = "2px solid #aaa";
20837 // appendChild can blow up IE if invoked prior to the window load event
20838 // while rendering a table. It is possible there are other scenarios
20839 // that would cause this to happen as well.
20840 body.insertBefore(div, body.firstChild);
20845 * Initialization for the drag frame element. Must be called in the
20846 * constructor of all subclasses
20847 * @method initFrame
20849 initFrame: function() {
20850 this.createFrame();
20853 applyConfig: function() {
20854 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20856 this.resizeFrame = (this.config.resizeFrame !== false);
20857 this.centerFrame = (this.config.centerFrame);
20858 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20862 * Resizes the drag frame to the dimensions of the clicked object, positions
20863 * it over the object, and finally displays it
20864 * @method showFrame
20865 * @param {int} iPageX X click position
20866 * @param {int} iPageY Y click position
20869 showFrame: function(iPageX, iPageY) {
20870 var el = this.getEl();
20871 var dragEl = this.getDragEl();
20872 var s = dragEl.style;
20874 this._resizeProxy();
20876 if (this.centerFrame) {
20877 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20878 Math.round(parseInt(s.height, 10)/2) );
20881 this.setDragElPos(iPageX, iPageY);
20883 Roo.fly(dragEl).show();
20887 * The proxy is automatically resized to the dimensions of the linked
20888 * element when a drag is initiated, unless resizeFrame is set to false
20889 * @method _resizeProxy
20892 _resizeProxy: function() {
20893 if (this.resizeFrame) {
20894 var el = this.getEl();
20895 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20899 // overrides Roo.dd.DragDrop
20900 b4MouseDown: function(e) {
20901 var x = e.getPageX();
20902 var y = e.getPageY();
20903 this.autoOffset(x, y);
20904 this.setDragElPos(x, y);
20907 // overrides Roo.dd.DragDrop
20908 b4StartDrag: function(x, y) {
20909 // show the drag frame
20910 this.showFrame(x, y);
20913 // overrides Roo.dd.DragDrop
20914 b4EndDrag: function(e) {
20915 Roo.fly(this.getDragEl()).hide();
20918 // overrides Roo.dd.DragDrop
20919 // By default we try to move the element to the last location of the frame.
20920 // This is so that the default behavior mirrors that of Roo.dd.DD.
20921 endDrag: function(e) {
20923 var lel = this.getEl();
20924 var del = this.getDragEl();
20926 // Show the drag frame briefly so we can get its position
20927 del.style.visibility = "";
20930 // Hide the linked element before the move to get around a Safari
20932 lel.style.visibility = "hidden";
20933 Roo.dd.DDM.moveToEl(lel, del);
20934 del.style.visibility = "hidden";
20935 lel.style.visibility = "";
20940 beforeMove : function(){
20944 afterDrag : function(){
20948 toString: function() {
20949 return ("DDProxy " + this.id);
20955 * Ext JS Library 1.1.1
20956 * Copyright(c) 2006-2007, Ext JS, LLC.
20958 * Originally Released Under LGPL - original licence link has changed is not relivant.
20961 * <script type="text/javascript">
20965 * @class Roo.dd.DDTarget
20966 * A DragDrop implementation that does not move, but can be a drop
20967 * target. You would get the same result by simply omitting implementation
20968 * for the event callbacks, but this way we reduce the processing cost of the
20969 * event listener and the callbacks.
20970 * @extends Roo.dd.DragDrop
20972 * @param {String} id the id of the element that is a drop target
20973 * @param {String} sGroup the group of related DragDrop objects
20974 * @param {object} config an object containing configurable attributes
20975 * Valid properties for DDTarget in addition to those in
20979 Roo.dd.DDTarget = function(id, sGroup, config) {
20981 this.initTarget(id, sGroup, config);
20983 if (config.listeners || config.events) {
20984 Roo.dd.DragDrop.superclass.constructor.call(this, {
20985 listeners : config.listeners || {},
20986 events : config.events || {}
20991 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20992 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20993 toString: function() {
20994 return ("DDTarget " + this.id);
20999 * Ext JS Library 1.1.1
21000 * Copyright(c) 2006-2007, Ext JS, LLC.
21002 * Originally Released Under LGPL - original licence link has changed is not relivant.
21005 * <script type="text/javascript">
21010 * @class Roo.dd.ScrollManager
21011 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21012 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21015 Roo.dd.ScrollManager = function(){
21016 var ddm = Roo.dd.DragDropMgr;
21023 var onStop = function(e){
21028 var triggerRefresh = function(){
21029 if(ddm.dragCurrent){
21030 ddm.refreshCache(ddm.dragCurrent.groups);
21034 var doScroll = function(){
21035 if(ddm.dragCurrent){
21036 var dds = Roo.dd.ScrollManager;
21038 if(proc.el.scroll(proc.dir, dds.increment)){
21042 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21047 var clearProc = function(){
21049 clearInterval(proc.id);
21056 var startProc = function(el, dir){
21057 Roo.log('scroll startproc');
21061 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21064 var onFire = function(e, isDrop){
21066 if(isDrop || !ddm.dragCurrent){ return; }
21067 var dds = Roo.dd.ScrollManager;
21068 if(!dragEl || dragEl != ddm.dragCurrent){
21069 dragEl = ddm.dragCurrent;
21070 // refresh regions on drag start
21071 dds.refreshCache();
21074 var xy = Roo.lib.Event.getXY(e);
21075 var pt = new Roo.lib.Point(xy[0], xy[1]);
21076 for(var id in els){
21077 var el = els[id], r = el._region;
21078 if(r && r.contains(pt) && el.isScrollable()){
21079 if(r.bottom - pt.y <= dds.thresh){
21081 startProc(el, "down");
21084 }else if(r.right - pt.x <= dds.thresh){
21086 startProc(el, "left");
21089 }else if(pt.y - r.top <= dds.thresh){
21091 startProc(el, "up");
21094 }else if(pt.x - r.left <= dds.thresh){
21096 startProc(el, "right");
21105 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21106 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21110 * Registers new overflow element(s) to auto scroll
21111 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21113 register : function(el){
21114 if(el instanceof Array){
21115 for(var i = 0, len = el.length; i < len; i++) {
21116 this.register(el[i]);
21122 Roo.dd.ScrollManager.els = els;
21126 * Unregisters overflow element(s) so they are no longer scrolled
21127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21129 unregister : function(el){
21130 if(el instanceof Array){
21131 for(var i = 0, len = el.length; i < len; i++) {
21132 this.unregister(el[i]);
21141 * The number of pixels from the edge of a container the pointer needs to be to
21142 * trigger scrolling (defaults to 25)
21148 * The number of pixels to scroll in each scroll increment (defaults to 50)
21154 * The frequency of scrolls in milliseconds (defaults to 500)
21160 * True to animate the scroll (defaults to true)
21166 * The animation duration in seconds -
21167 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21173 * Manually trigger a cache refresh.
21175 refreshCache : function(){
21176 for(var id in els){
21177 if(typeof els[id] == 'object'){ // for people extending the object prototype
21178 els[id]._region = els[id].getRegion();
21185 * Ext JS Library 1.1.1
21186 * Copyright(c) 2006-2007, Ext JS, LLC.
21188 * Originally Released Under LGPL - original licence link has changed is not relivant.
21191 * <script type="text/javascript">
21196 * @class Roo.dd.Registry
21197 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21198 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21201 Roo.dd.Registry = function(){
21204 var autoIdSeed = 0;
21206 var getId = function(el, autogen){
21207 if(typeof el == "string"){
21211 if(!id && autogen !== false){
21212 id = "roodd-" + (++autoIdSeed);
21220 * Register a drag drop element
21221 * @param {String|HTMLElement} element The id or DOM node to register
21222 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21223 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21224 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21225 * populated in the data object (if applicable):
21227 Value Description<br />
21228 --------- ------------------------------------------<br />
21229 handles Array of DOM nodes that trigger dragging<br />
21230 for the element being registered<br />
21231 isHandle True if the element passed in triggers<br />
21232 dragging itself, else false
21235 register : function(el, data){
21237 if(typeof el == "string"){
21238 el = document.getElementById(el);
21241 elements[getId(el)] = data;
21242 if(data.isHandle !== false){
21243 handles[data.ddel.id] = data;
21246 var hs = data.handles;
21247 for(var i = 0, len = hs.length; i < len; i++){
21248 handles[getId(hs[i])] = data;
21254 * Unregister a drag drop element
21255 * @param {String|HTMLElement} element The id or DOM node to unregister
21257 unregister : function(el){
21258 var id = getId(el, false);
21259 var data = elements[id];
21261 delete elements[id];
21263 var hs = data.handles;
21264 for(var i = 0, len = hs.length; i < len; i++){
21265 delete handles[getId(hs[i], false)];
21272 * Returns the handle registered for a DOM Node by id
21273 * @param {String|HTMLElement} id The DOM node or id to look up
21274 * @return {Object} handle The custom handle data
21276 getHandle : function(id){
21277 if(typeof id != "string"){ // must be element?
21280 return handles[id];
21284 * Returns the handle that is registered for the DOM node that is the target of the event
21285 * @param {Event} e The event
21286 * @return {Object} handle The custom handle data
21288 getHandleFromEvent : function(e){
21289 var t = Roo.lib.Event.getTarget(e);
21290 return t ? handles[t.id] : null;
21294 * Returns a custom data object that is registered for a DOM node by id
21295 * @param {String|HTMLElement} id The DOM node or id to look up
21296 * @return {Object} data The custom data
21298 getTarget : function(id){
21299 if(typeof id != "string"){ // must be element?
21302 return elements[id];
21306 * Returns a custom data object that is registered for the DOM node that is the target of the event
21307 * @param {Event} e The event
21308 * @return {Object} data The custom data
21310 getTargetFromEvent : function(e){
21311 var t = Roo.lib.Event.getTarget(e);
21312 return t ? elements[t.id] || handles[t.id] : null;
21317 * Ext JS Library 1.1.1
21318 * Copyright(c) 2006-2007, Ext JS, LLC.
21320 * Originally Released Under LGPL - original licence link has changed is not relivant.
21323 * <script type="text/javascript">
21328 * @class Roo.dd.StatusProxy
21329 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21330 * default drag proxy used by all Roo.dd components.
21332 * @param {Object} config
21334 Roo.dd.StatusProxy = function(config){
21335 Roo.apply(this, config);
21336 this.id = this.id || Roo.id();
21337 this.el = new Roo.Layer({
21339 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21340 {tag: "div", cls: "x-dd-drop-icon"},
21341 {tag: "div", cls: "x-dd-drag-ghost"}
21344 shadow: !config || config.shadow !== false
21346 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21347 this.dropStatus = this.dropNotAllowed;
21350 Roo.dd.StatusProxy.prototype = {
21352 * @cfg {String} dropAllowed
21353 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21355 dropAllowed : "x-dd-drop-ok",
21357 * @cfg {String} dropNotAllowed
21358 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21360 dropNotAllowed : "x-dd-drop-nodrop",
21363 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21364 * over the current target element.
21365 * @param {String} cssClass The css class for the new drop status indicator image
21367 setStatus : function(cssClass){
21368 cssClass = cssClass || this.dropNotAllowed;
21369 if(this.dropStatus != cssClass){
21370 this.el.replaceClass(this.dropStatus, cssClass);
21371 this.dropStatus = cssClass;
21376 * Resets the status indicator to the default dropNotAllowed value
21377 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21379 reset : function(clearGhost){
21380 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21381 this.dropStatus = this.dropNotAllowed;
21383 this.ghost.update("");
21388 * Updates the contents of the ghost element
21389 * @param {String} html The html that will replace the current innerHTML of the ghost element
21391 update : function(html){
21392 if(typeof html == "string"){
21393 this.ghost.update(html);
21395 this.ghost.update("");
21396 html.style.margin = "0";
21397 this.ghost.dom.appendChild(html);
21399 // ensure float = none set?? cant remember why though.
21400 var el = this.ghost.dom.firstChild;
21402 Roo.fly(el).setStyle('float', 'none');
21407 * Returns the underlying proxy {@link Roo.Layer}
21408 * @return {Roo.Layer} el
21410 getEl : function(){
21415 * Returns the ghost element
21416 * @return {Roo.Element} el
21418 getGhost : function(){
21424 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21426 hide : function(clear){
21434 * Stops the repair animation if it's currently running
21437 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21443 * Displays this proxy
21450 * Force the Layer to sync its shadow and shim positions to the element
21457 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21458 * invalid drop operation by the item being dragged.
21459 * @param {Array} xy The XY position of the element ([x, y])
21460 * @param {Function} callback The function to call after the repair is complete
21461 * @param {Object} scope The scope in which to execute the callback
21463 repair : function(xy, callback, scope){
21464 this.callback = callback;
21465 this.scope = scope;
21466 if(xy && this.animRepair !== false){
21467 this.el.addClass("x-dd-drag-repair");
21468 this.el.hideUnders(true);
21469 this.anim = this.el.shift({
21470 duration: this.repairDuration || .5,
21474 callback: this.afterRepair,
21478 this.afterRepair();
21483 afterRepair : function(){
21485 if(typeof this.callback == "function"){
21486 this.callback.call(this.scope || this);
21488 this.callback = null;
21493 * Ext JS Library 1.1.1
21494 * Copyright(c) 2006-2007, Ext JS, LLC.
21496 * Originally Released Under LGPL - original licence link has changed is not relivant.
21499 * <script type="text/javascript">
21503 * @class Roo.dd.DragSource
21504 * @extends Roo.dd.DDProxy
21505 * A simple class that provides the basic implementation needed to make any element draggable.
21507 * @param {String/HTMLElement/Element} el The container element
21508 * @param {Object} config
21510 Roo.dd.DragSource = function(el, config){
21511 this.el = Roo.get(el);
21512 this.dragData = {};
21514 Roo.apply(this, config);
21517 this.proxy = new Roo.dd.StatusProxy();
21520 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21521 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21523 this.dragging = false;
21526 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21528 * @cfg {String} dropAllowed
21529 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21531 dropAllowed : "x-dd-drop-ok",
21533 * @cfg {String} dropNotAllowed
21534 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21536 dropNotAllowed : "x-dd-drop-nodrop",
21539 * Returns the data object associated with this drag source
21540 * @return {Object} data An object containing arbitrary data
21542 getDragData : function(e){
21543 return this.dragData;
21547 onDragEnter : function(e, id){
21548 var target = Roo.dd.DragDropMgr.getDDById(id);
21549 this.cachedTarget = target;
21550 if(this.beforeDragEnter(target, e, id) !== false){
21551 if(target.isNotifyTarget){
21552 var status = target.notifyEnter(this, e, this.dragData);
21553 this.proxy.setStatus(status);
21555 this.proxy.setStatus(this.dropAllowed);
21558 if(this.afterDragEnter){
21560 * An empty function by default, but provided so that you can perform a custom action
21561 * when the dragged item enters the drop target by providing an implementation.
21562 * @param {Roo.dd.DragDrop} target The drop target
21563 * @param {Event} e The event object
21564 * @param {String} id The id of the dragged element
21565 * @method afterDragEnter
21567 this.afterDragEnter(target, e, id);
21573 * An empty function by default, but provided so that you can perform a custom action
21574 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21575 * @param {Roo.dd.DragDrop} target The drop target
21576 * @param {Event} e The event object
21577 * @param {String} id The id of the dragged element
21578 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21580 beforeDragEnter : function(target, e, id){
21585 alignElWithMouse: function() {
21586 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21591 onDragOver : function(e, id){
21592 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21593 if(this.beforeDragOver(target, e, id) !== false){
21594 if(target.isNotifyTarget){
21595 var status = target.notifyOver(this, e, this.dragData);
21596 this.proxy.setStatus(status);
21599 if(this.afterDragOver){
21601 * An empty function by default, but provided so that you can perform a custom action
21602 * while the dragged item is over the drop target by providing an implementation.
21603 * @param {Roo.dd.DragDrop} target The drop target
21604 * @param {Event} e The event object
21605 * @param {String} id The id of the dragged element
21606 * @method afterDragOver
21608 this.afterDragOver(target, e, id);
21614 * An empty function by default, but provided so that you can perform a custom action
21615 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21616 * @param {Roo.dd.DragDrop} target The drop target
21617 * @param {Event} e The event object
21618 * @param {String} id The id of the dragged element
21619 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21621 beforeDragOver : function(target, e, id){
21626 onDragOut : function(e, id){
21627 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21628 if(this.beforeDragOut(target, e, id) !== false){
21629 if(target.isNotifyTarget){
21630 target.notifyOut(this, e, this.dragData);
21632 this.proxy.reset();
21633 if(this.afterDragOut){
21635 * An empty function by default, but provided so that you can perform a custom action
21636 * after the dragged item is dragged out of the target without dropping.
21637 * @param {Roo.dd.DragDrop} target The drop target
21638 * @param {Event} e The event object
21639 * @param {String} id The id of the dragged element
21640 * @method afterDragOut
21642 this.afterDragOut(target, e, id);
21645 this.cachedTarget = null;
21649 * An empty function by default, but provided so that you can perform a custom action before the dragged
21650 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21651 * @param {Roo.dd.DragDrop} target The drop target
21652 * @param {Event} e The event object
21653 * @param {String} id The id of the dragged element
21654 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21656 beforeDragOut : function(target, e, id){
21661 onDragDrop : function(e, id){
21662 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21663 if(this.beforeDragDrop(target, e, id) !== false){
21664 if(target.isNotifyTarget){
21665 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21666 this.onValidDrop(target, e, id);
21668 this.onInvalidDrop(target, e, id);
21671 this.onValidDrop(target, e, id);
21674 if(this.afterDragDrop){
21676 * An empty function by default, but provided so that you can perform a custom action
21677 * after a valid drag drop has occurred by providing an implementation.
21678 * @param {Roo.dd.DragDrop} target The drop target
21679 * @param {Event} e The event object
21680 * @param {String} id The id of the dropped element
21681 * @method afterDragDrop
21683 this.afterDragDrop(target, e, id);
21686 delete this.cachedTarget;
21690 * An empty function by default, but provided so that you can perform a custom action before the dragged
21691 * item is dropped onto the target and optionally cancel the onDragDrop.
21692 * @param {Roo.dd.DragDrop} target The drop target
21693 * @param {Event} e The event object
21694 * @param {String} id The id of the dragged element
21695 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21697 beforeDragDrop : function(target, e, id){
21702 onValidDrop : function(target, e, id){
21704 if(this.afterValidDrop){
21706 * An empty function by default, but provided so that you can perform a custom action
21707 * after a valid drop has occurred by providing an implementation.
21708 * @param {Object} target The target DD
21709 * @param {Event} e The event object
21710 * @param {String} id The id of the dropped element
21711 * @method afterInvalidDrop
21713 this.afterValidDrop(target, e, id);
21718 getRepairXY : function(e, data){
21719 return this.el.getXY();
21723 onInvalidDrop : function(target, e, id){
21724 this.beforeInvalidDrop(target, e, id);
21725 if(this.cachedTarget){
21726 if(this.cachedTarget.isNotifyTarget){
21727 this.cachedTarget.notifyOut(this, e, this.dragData);
21729 this.cacheTarget = null;
21731 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21733 if(this.afterInvalidDrop){
21735 * An empty function by default, but provided so that you can perform a custom action
21736 * after an invalid drop has occurred by providing an implementation.
21737 * @param {Event} e The event object
21738 * @param {String} id The id of the dropped element
21739 * @method afterInvalidDrop
21741 this.afterInvalidDrop(e, id);
21746 afterRepair : function(){
21748 this.el.highlight(this.hlColor || "c3daf9");
21750 this.dragging = false;
21754 * An empty function by default, but provided so that you can perform a custom action after an invalid
21755 * drop has occurred.
21756 * @param {Roo.dd.DragDrop} target The drop target
21757 * @param {Event} e The event object
21758 * @param {String} id The id of the dragged element
21759 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21761 beforeInvalidDrop : function(target, e, id){
21766 handleMouseDown : function(e){
21767 if(this.dragging) {
21770 var data = this.getDragData(e);
21771 if(data && this.onBeforeDrag(data, e) !== false){
21772 this.dragData = data;
21774 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21779 * An empty function by default, but provided so that you can perform a custom action before the initial
21780 * drag event begins and optionally cancel it.
21781 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21782 * @param {Event} e The event object
21783 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21785 onBeforeDrag : function(data, e){
21790 * An empty function by default, but provided so that you can perform a custom action once the initial
21791 * drag event has begun. The drag cannot be canceled from this function.
21792 * @param {Number} x The x position of the click on the dragged object
21793 * @param {Number} y The y position of the click on the dragged object
21795 onStartDrag : Roo.emptyFn,
21797 // private - YUI override
21798 startDrag : function(x, y){
21799 this.proxy.reset();
21800 this.dragging = true;
21801 this.proxy.update("");
21802 this.onInitDrag(x, y);
21807 onInitDrag : function(x, y){
21808 var clone = this.el.dom.cloneNode(true);
21809 clone.id = Roo.id(); // prevent duplicate ids
21810 this.proxy.update(clone);
21811 this.onStartDrag(x, y);
21816 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21817 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21819 getProxy : function(){
21824 * Hides the drag source's {@link Roo.dd.StatusProxy}
21826 hideProxy : function(){
21828 this.proxy.reset(true);
21829 this.dragging = false;
21833 triggerCacheRefresh : function(){
21834 Roo.dd.DDM.refreshCache(this.groups);
21837 // private - override to prevent hiding
21838 b4EndDrag: function(e) {
21841 // private - override to prevent moving
21842 endDrag : function(e){
21843 this.onEndDrag(this.dragData, e);
21847 onEndDrag : function(data, e){
21850 // private - pin to cursor
21851 autoOffset : function(x, y) {
21852 this.setDelta(-12, -20);
21856 * Ext JS Library 1.1.1
21857 * Copyright(c) 2006-2007, Ext JS, LLC.
21859 * Originally Released Under LGPL - original licence link has changed is not relivant.
21862 * <script type="text/javascript">
21867 * @class Roo.dd.DropTarget
21868 * @extends Roo.dd.DDTarget
21869 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21870 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21872 * @param {String/HTMLElement/Element} el The container element
21873 * @param {Object} config
21875 Roo.dd.DropTarget = function(el, config){
21876 this.el = Roo.get(el);
21878 var listeners = false; ;
21879 if (config && config.listeners) {
21880 listeners= config.listeners;
21881 delete config.listeners;
21883 Roo.apply(this, config);
21885 if(this.containerScroll){
21886 Roo.dd.ScrollManager.register(this.el);
21890 * @scope Roo.dd.DropTarget
21895 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21896 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21897 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21899 * IMPORTANT : it should set this.overClass and this.dropAllowed
21901 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21902 * @param {Event} e The event
21903 * @param {Object} data An object containing arbitrary data supplied by the drag source
21909 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21910 * This method will be called on every mouse movement while the drag source is over the drop target.
21911 * This default implementation simply returns the dropAllowed config value.
21913 * IMPORTANT : it should set this.dropAllowed
21915 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21916 * @param {Event} e The event
21917 * @param {Object} data An object containing arbitrary data supplied by the drag source
21923 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21924 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21925 * overClass (if any) from the drop element.
21927 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21928 * @param {Event} e The event
21929 * @param {Object} data An object containing arbitrary data supplied by the drag source
21935 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21936 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21937 * implementation that does something to process the drop event and returns true so that the drag source's
21938 * repair action does not run.
21940 * IMPORTANT : it should set this.success
21942 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21943 * @param {Event} e The event
21944 * @param {Object} data An object containing arbitrary data supplied by the drag source
21950 Roo.dd.DropTarget.superclass.constructor.call( this,
21952 this.ddGroup || this.group,
21955 listeners : listeners || {}
21963 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21965 * @cfg {String} overClass
21966 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21969 * @cfg {String} ddGroup
21970 * The drag drop group to handle drop events for
21974 * @cfg {String} dropAllowed
21975 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21977 dropAllowed : "x-dd-drop-ok",
21979 * @cfg {String} dropNotAllowed
21980 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21982 dropNotAllowed : "x-dd-drop-nodrop",
21984 * @cfg {boolean} success
21985 * set this after drop listener..
21989 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21990 * if the drop point is valid for over/enter..
21997 isNotifyTarget : true,
22002 notifyEnter : function(dd, e, data)
22005 this.fireEvent('enter', dd, e, data);
22006 if(this.overClass){
22007 this.el.addClass(this.overClass);
22009 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22010 this.valid ? this.dropAllowed : this.dropNotAllowed
22017 notifyOver : function(dd, e, data)
22020 this.fireEvent('over', dd, e, data);
22021 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22022 this.valid ? this.dropAllowed : this.dropNotAllowed
22029 notifyOut : function(dd, e, data)
22031 this.fireEvent('out', dd, e, data);
22032 if(this.overClass){
22033 this.el.removeClass(this.overClass);
22040 notifyDrop : function(dd, e, data)
22042 this.success = false;
22043 this.fireEvent('drop', dd, e, data);
22044 return this.success;
22048 * Ext JS Library 1.1.1
22049 * Copyright(c) 2006-2007, Ext JS, LLC.
22051 * Originally Released Under LGPL - original licence link has changed is not relivant.
22054 * <script type="text/javascript">
22059 * @class Roo.dd.DragZone
22060 * @extends Roo.dd.DragSource
22061 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22062 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22064 * @param {String/HTMLElement/Element} el The container element
22065 * @param {Object} config
22067 Roo.dd.DragZone = function(el, config){
22068 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22069 if(this.containerScroll){
22070 Roo.dd.ScrollManager.register(this.el);
22074 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22076 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22077 * for auto scrolling during drag operations.
22080 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22081 * method after a failed drop (defaults to "c3daf9" - light blue)
22085 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22086 * for a valid target to drag based on the mouse down. Override this method
22087 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22088 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22089 * @param {EventObject} e The mouse down event
22090 * @return {Object} The dragData
22092 getDragData : function(e){
22093 return Roo.dd.Registry.getHandleFromEvent(e);
22097 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22098 * this.dragData.ddel
22099 * @param {Number} x The x position of the click on the dragged object
22100 * @param {Number} y The y position of the click on the dragged object
22101 * @return {Boolean} true to continue the drag, false to cancel
22103 onInitDrag : function(x, y){
22104 this.proxy.update(this.dragData.ddel.cloneNode(true));
22105 this.onStartDrag(x, y);
22110 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22112 afterRepair : function(){
22114 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22116 this.dragging = false;
22120 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22121 * the XY of this.dragData.ddel
22122 * @param {EventObject} e The mouse up event
22123 * @return {Array} The xy location (e.g. [100, 200])
22125 getRepairXY : function(e){
22126 return Roo.Element.fly(this.dragData.ddel).getXY();
22130 * Ext JS Library 1.1.1
22131 * Copyright(c) 2006-2007, Ext JS, LLC.
22133 * Originally Released Under LGPL - original licence link has changed is not relivant.
22136 * <script type="text/javascript">
22139 * @class Roo.dd.DropZone
22140 * @extends Roo.dd.DropTarget
22141 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22142 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22144 * @param {String/HTMLElement/Element} el The container element
22145 * @param {Object} config
22147 Roo.dd.DropZone = function(el, config){
22148 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22151 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22153 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22154 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22155 * provide your own custom lookup.
22156 * @param {Event} e The event
22157 * @return {Object} data The custom data
22159 getTargetFromEvent : function(e){
22160 return Roo.dd.Registry.getTargetFromEvent(e);
22164 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22165 * that it has registered. This method has no default implementation and should be overridden to provide
22166 * node-specific processing if necessary.
22167 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22168 * {@link #getTargetFromEvent} for this node)
22169 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22170 * @param {Event} e The event
22171 * @param {Object} data An object containing arbitrary data supplied by the drag source
22173 onNodeEnter : function(n, dd, e, data){
22178 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22179 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22180 * overridden to provide the proper feedback.
22181 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22182 * {@link #getTargetFromEvent} for this node)
22183 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22184 * @param {Event} e The event
22185 * @param {Object} data An object containing arbitrary data supplied by the drag source
22186 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22187 * underlying {@link Roo.dd.StatusProxy} can be updated
22189 onNodeOver : function(n, dd, e, data){
22190 return this.dropAllowed;
22194 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22195 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22196 * node-specific processing if necessary.
22197 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22198 * {@link #getTargetFromEvent} for this node)
22199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200 * @param {Event} e The event
22201 * @param {Object} data An object containing arbitrary data supplied by the drag source
22203 onNodeOut : function(n, dd, e, data){
22208 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22209 * the drop node. The default implementation returns false, so it should be overridden to provide the
22210 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22211 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22212 * {@link #getTargetFromEvent} for this node)
22213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22214 * @param {Event} e The event
22215 * @param {Object} data An object containing arbitrary data supplied by the drag source
22216 * @return {Boolean} True if the drop was valid, else false
22218 onNodeDrop : function(n, dd, e, data){
22223 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22224 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22225 * it should be overridden to provide the proper feedback if necessary.
22226 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22227 * @param {Event} e The event
22228 * @param {Object} data An object containing arbitrary data supplied by the drag source
22229 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22230 * underlying {@link Roo.dd.StatusProxy} can be updated
22232 onContainerOver : function(dd, e, data){
22233 return this.dropNotAllowed;
22237 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22238 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22239 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22240 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22241 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22242 * @param {Event} e The event
22243 * @param {Object} data An object containing arbitrary data supplied by the drag source
22244 * @return {Boolean} True if the drop was valid, else false
22246 onContainerDrop : function(dd, e, data){
22251 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22252 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22253 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22254 * you should override this method and provide a custom implementation.
22255 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22256 * @param {Event} e The event
22257 * @param {Object} data An object containing arbitrary data supplied by the drag source
22258 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22259 * underlying {@link Roo.dd.StatusProxy} can be updated
22261 notifyEnter : function(dd, e, data){
22262 return this.dropNotAllowed;
22266 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22267 * This method will be called on every mouse movement while the drag source is over the drop zone.
22268 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22269 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22270 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22271 * registered node, it will call {@link #onContainerOver}.
22272 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22273 * @param {Event} e The event
22274 * @param {Object} data An object containing arbitrary data supplied by the drag source
22275 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22276 * underlying {@link Roo.dd.StatusProxy} can be updated
22278 notifyOver : function(dd, e, data){
22279 var n = this.getTargetFromEvent(e);
22280 if(!n){ // not over valid drop target
22281 if(this.lastOverNode){
22282 this.onNodeOut(this.lastOverNode, dd, e, data);
22283 this.lastOverNode = null;
22285 return this.onContainerOver(dd, e, data);
22287 if(this.lastOverNode != n){
22288 if(this.lastOverNode){
22289 this.onNodeOut(this.lastOverNode, dd, e, data);
22291 this.onNodeEnter(n, dd, e, data);
22292 this.lastOverNode = n;
22294 return this.onNodeOver(n, dd, e, data);
22298 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22299 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22300 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22301 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22302 * @param {Event} e The event
22303 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22305 notifyOut : function(dd, e, data){
22306 if(this.lastOverNode){
22307 this.onNodeOut(this.lastOverNode, dd, e, data);
22308 this.lastOverNode = null;
22313 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22314 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22315 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22316 * otherwise it will call {@link #onContainerDrop}.
22317 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22318 * @param {Event} e The event
22319 * @param {Object} data An object containing arbitrary data supplied by the drag source
22320 * @return {Boolean} True if the drop was valid, else false
22322 notifyDrop : function(dd, e, data){
22323 if(this.lastOverNode){
22324 this.onNodeOut(this.lastOverNode, dd, e, data);
22325 this.lastOverNode = null;
22327 var n = this.getTargetFromEvent(e);
22329 this.onNodeDrop(n, dd, e, data) :
22330 this.onContainerDrop(dd, e, data);
22334 triggerCacheRefresh : function(){
22335 Roo.dd.DDM.refreshCache(this.groups);
22339 * Ext JS Library 1.1.1
22340 * Copyright(c) 2006-2007, Ext JS, LLC.
22342 * Originally Released Under LGPL - original licence link has changed is not relivant.
22345 * <script type="text/javascript">
22350 * @class Roo.data.SortTypes
22352 * Defines the default sorting (casting?) comparison functions used when sorting data.
22354 Roo.data.SortTypes = {
22356 * Default sort that does nothing
22357 * @param {Mixed} s The value being converted
22358 * @return {Mixed} The comparison value
22360 none : function(s){
22365 * The regular expression used to strip tags
22369 stripTagsRE : /<\/?[^>]+>/gi,
22372 * Strips all HTML tags to sort on text only
22373 * @param {Mixed} s The value being converted
22374 * @return {String} The comparison value
22376 asText : function(s){
22377 return String(s).replace(this.stripTagsRE, "");
22381 * Strips all HTML tags to sort on text only - Case insensitive
22382 * @param {Mixed} s The value being converted
22383 * @return {String} The comparison value
22385 asUCText : function(s){
22386 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22390 * Case insensitive string
22391 * @param {Mixed} s The value being converted
22392 * @return {String} The comparison value
22394 asUCString : function(s) {
22395 return String(s).toUpperCase();
22400 * @param {Mixed} s The value being converted
22401 * @return {Number} The comparison value
22403 asDate : function(s) {
22407 if(s instanceof Date){
22408 return s.getTime();
22410 return Date.parse(String(s));
22415 * @param {Mixed} s The value being converted
22416 * @return {Float} The comparison value
22418 asFloat : function(s) {
22419 var val = parseFloat(String(s).replace(/,/g, ""));
22428 * @param {Mixed} s The value being converted
22429 * @return {Number} The comparison value
22431 asInt : function(s) {
22432 var val = parseInt(String(s).replace(/,/g, ""));
22440 * Ext JS Library 1.1.1
22441 * Copyright(c) 2006-2007, Ext JS, LLC.
22443 * Originally Released Under LGPL - original licence link has changed is not relivant.
22446 * <script type="text/javascript">
22450 * @class Roo.data.Record
22451 * Instances of this class encapsulate both record <em>definition</em> information, and record
22452 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22453 * to access Records cached in an {@link Roo.data.Store} object.<br>
22455 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22456 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22459 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22461 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22462 * {@link #create}. The parameters are the same.
22463 * @param {Array} data An associative Array of data values keyed by the field name.
22464 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22465 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22466 * not specified an integer id is generated.
22468 Roo.data.Record = function(data, id){
22469 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22474 * Generate a constructor for a specific record layout.
22475 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22476 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22477 * Each field definition object may contain the following properties: <ul>
22478 * <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,
22479 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22480 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22481 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22482 * is being used, then this is a string containing the javascript expression to reference the data relative to
22483 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22484 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22485 * this may be omitted.</p></li>
22486 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22487 * <ul><li>auto (Default, implies no conversion)</li>
22492 * <li>date</li></ul></p></li>
22493 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22494 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22495 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22496 * by the Reader into an object that will be stored in the Record. It is passed the
22497 * following parameters:<ul>
22498 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22500 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22502 * <br>usage:<br><pre><code>
22503 var TopicRecord = Roo.data.Record.create(
22504 {name: 'title', mapping: 'topic_title'},
22505 {name: 'author', mapping: 'username'},
22506 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22507 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22508 {name: 'lastPoster', mapping: 'user2'},
22509 {name: 'excerpt', mapping: 'post_text'}
22512 var myNewRecord = new TopicRecord({
22513 title: 'Do my job please',
22516 lastPost: new Date(),
22517 lastPoster: 'Animal',
22518 excerpt: 'No way dude!'
22520 myStore.add(myNewRecord);
22525 Roo.data.Record.create = function(o){
22526 var f = function(){
22527 f.superclass.constructor.apply(this, arguments);
22529 Roo.extend(f, Roo.data.Record);
22530 var p = f.prototype;
22531 p.fields = new Roo.util.MixedCollection(false, function(field){
22534 for(var i = 0, len = o.length; i < len; i++){
22535 p.fields.add(new Roo.data.Field(o[i]));
22537 f.getField = function(name){
22538 return p.fields.get(name);
22543 Roo.data.Record.AUTO_ID = 1000;
22544 Roo.data.Record.EDIT = 'edit';
22545 Roo.data.Record.REJECT = 'reject';
22546 Roo.data.Record.COMMIT = 'commit';
22548 Roo.data.Record.prototype = {
22550 * Readonly flag - true if this record has been modified.
22559 join : function(store){
22560 this.store = store;
22564 * Set the named field to the specified value.
22565 * @param {String} name The name of the field to set.
22566 * @param {Object} value The value to set the field to.
22568 set : function(name, value){
22569 if(this.data[name] == value){
22573 if(!this.modified){
22574 this.modified = {};
22576 if(typeof this.modified[name] == 'undefined'){
22577 this.modified[name] = this.data[name];
22579 this.data[name] = value;
22580 if(!this.editing && this.store){
22581 this.store.afterEdit(this);
22586 * Get the value of the named field.
22587 * @param {String} name The name of the field to get the value of.
22588 * @return {Object} The value of the field.
22590 get : function(name){
22591 return this.data[name];
22595 beginEdit : function(){
22596 this.editing = true;
22597 this.modified = {};
22601 cancelEdit : function(){
22602 this.editing = false;
22603 delete this.modified;
22607 endEdit : function(){
22608 this.editing = false;
22609 if(this.dirty && this.store){
22610 this.store.afterEdit(this);
22615 * Usually called by the {@link Roo.data.Store} which owns the Record.
22616 * Rejects all changes made to the Record since either creation, or the last commit operation.
22617 * Modified fields are reverted to their original values.
22619 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22620 * of reject operations.
22622 reject : function(){
22623 var m = this.modified;
22625 if(typeof m[n] != "function"){
22626 this.data[n] = m[n];
22629 this.dirty = false;
22630 delete this.modified;
22631 this.editing = false;
22633 this.store.afterReject(this);
22638 * Usually called by the {@link Roo.data.Store} which owns the Record.
22639 * Commits all changes made to the Record since either creation, or the last commit operation.
22641 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22642 * of commit operations.
22644 commit : function(){
22645 this.dirty = false;
22646 delete this.modified;
22647 this.editing = false;
22649 this.store.afterCommit(this);
22654 hasError : function(){
22655 return this.error != null;
22659 clearError : function(){
22664 * Creates a copy of this record.
22665 * @param {String} id (optional) A new record id if you don't want to use this record's id
22668 copy : function(newId) {
22669 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22673 * Ext JS Library 1.1.1
22674 * Copyright(c) 2006-2007, Ext JS, LLC.
22676 * Originally Released Under LGPL - original licence link has changed is not relivant.
22679 * <script type="text/javascript">
22685 * @class Roo.data.Store
22686 * @extends Roo.util.Observable
22687 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22688 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22690 * 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
22691 * has no knowledge of the format of the data returned by the Proxy.<br>
22693 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22694 * instances from the data object. These records are cached and made available through accessor functions.
22696 * Creates a new Store.
22697 * @param {Object} config A config object containing the objects needed for the Store to access data,
22698 * and read the data into Records.
22700 Roo.data.Store = function(config){
22701 this.data = new Roo.util.MixedCollection(false);
22702 this.data.getKey = function(o){
22705 this.baseParams = {};
22707 this.paramNames = {
22712 "multisort" : "_multisort"
22715 if(config && config.data){
22716 this.inlineData = config.data;
22717 delete config.data;
22720 Roo.apply(this, config);
22722 if(this.reader){ // reader passed
22723 this.reader = Roo.factory(this.reader, Roo.data);
22724 this.reader.xmodule = this.xmodule || false;
22725 if(!this.recordType){
22726 this.recordType = this.reader.recordType;
22728 if(this.reader.onMetaChange){
22729 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22733 if(this.recordType){
22734 this.fields = this.recordType.prototype.fields;
22736 this.modified = [];
22740 * @event datachanged
22741 * Fires when the data cache has changed, and a widget which is using this Store
22742 * as a Record cache should refresh its view.
22743 * @param {Store} this
22745 datachanged : true,
22747 * @event metachange
22748 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22749 * @param {Store} this
22750 * @param {Object} meta The JSON metadata
22755 * Fires when Records have been added to the Store
22756 * @param {Store} this
22757 * @param {Roo.data.Record[]} records The array of Records added
22758 * @param {Number} index The index at which the record(s) were added
22763 * Fires when a Record has been removed from the Store
22764 * @param {Store} this
22765 * @param {Roo.data.Record} record The Record that was removed
22766 * @param {Number} index The index at which the record was removed
22771 * Fires when a Record has been updated
22772 * @param {Store} this
22773 * @param {Roo.data.Record} record The Record that was updated
22774 * @param {String} operation The update operation being performed. Value may be one of:
22776 Roo.data.Record.EDIT
22777 Roo.data.Record.REJECT
22778 Roo.data.Record.COMMIT
22784 * Fires when the data cache has been cleared.
22785 * @param {Store} this
22789 * @event beforeload
22790 * Fires before a request is made for a new data object. If the beforeload handler returns false
22791 * the load action will be canceled.
22792 * @param {Store} this
22793 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22797 * @event beforeloadadd
22798 * Fires after a new set of Records has been loaded.
22799 * @param {Store} this
22800 * @param {Roo.data.Record[]} records The Records that were loaded
22801 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22803 beforeloadadd : true,
22806 * Fires after a new set of Records has been loaded, before they are added to the store.
22807 * @param {Store} this
22808 * @param {Roo.data.Record[]} records The Records that were loaded
22809 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22810 * @params {Object} return from reader
22814 * @event loadexception
22815 * Fires if an exception occurs in the Proxy during loading.
22816 * Called with the signature of the Proxy's "loadexception" event.
22817 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22820 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22821 * @param {Object} load options
22822 * @param {Object} jsonData from your request (normally this contains the Exception)
22824 loadexception : true
22828 this.proxy = Roo.factory(this.proxy, Roo.data);
22829 this.proxy.xmodule = this.xmodule || false;
22830 this.relayEvents(this.proxy, ["loadexception"]);
22832 this.sortToggle = {};
22833 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22835 Roo.data.Store.superclass.constructor.call(this);
22837 if(this.inlineData){
22838 this.loadData(this.inlineData);
22839 delete this.inlineData;
22843 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22845 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22846 * without a remote query - used by combo/forms at present.
22850 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22853 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22856 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22857 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22860 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22861 * on any HTTP request
22864 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22867 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22871 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22872 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22874 remoteSort : false,
22877 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22878 * loaded or when a record is removed. (defaults to false).
22880 pruneModifiedRecords : false,
22883 lastOptions : null,
22886 * Add Records to the Store and fires the add event.
22887 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22889 add : function(records){
22890 records = [].concat(records);
22891 for(var i = 0, len = records.length; i < len; i++){
22892 records[i].join(this);
22894 var index = this.data.length;
22895 this.data.addAll(records);
22896 this.fireEvent("add", this, records, index);
22900 * Remove a Record from the Store and fires the remove event.
22901 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22903 remove : function(record){
22904 var index = this.data.indexOf(record);
22905 this.data.removeAt(index);
22906 if(this.pruneModifiedRecords){
22907 this.modified.remove(record);
22909 this.fireEvent("remove", this, record, index);
22913 * Remove all Records from the Store and fires the clear event.
22915 removeAll : function(){
22917 if(this.pruneModifiedRecords){
22918 this.modified = [];
22920 this.fireEvent("clear", this);
22924 * Inserts Records to the Store at the given index and fires the add event.
22925 * @param {Number} index The start index at which to insert the passed Records.
22926 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22928 insert : function(index, records){
22929 records = [].concat(records);
22930 for(var i = 0, len = records.length; i < len; i++){
22931 this.data.insert(index, records[i]);
22932 records[i].join(this);
22934 this.fireEvent("add", this, records, index);
22938 * Get the index within the cache of the passed Record.
22939 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22940 * @return {Number} The index of the passed Record. Returns -1 if not found.
22942 indexOf : function(record){
22943 return this.data.indexOf(record);
22947 * Get the index within the cache of the Record with the passed id.
22948 * @param {String} id The id of the Record to find.
22949 * @return {Number} The index of the Record. Returns -1 if not found.
22951 indexOfId : function(id){
22952 return this.data.indexOfKey(id);
22956 * Get the Record with the specified id.
22957 * @param {String} id The id of the Record to find.
22958 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22960 getById : function(id){
22961 return this.data.key(id);
22965 * Get the Record at the specified index.
22966 * @param {Number} index The index of the Record to find.
22967 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22969 getAt : function(index){
22970 return this.data.itemAt(index);
22974 * Returns a range of Records between specified indices.
22975 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22976 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22977 * @return {Roo.data.Record[]} An array of Records
22979 getRange : function(start, end){
22980 return this.data.getRange(start, end);
22984 storeOptions : function(o){
22985 o = Roo.apply({}, o);
22988 this.lastOptions = o;
22992 * Loads the Record cache from the configured Proxy using the configured Reader.
22994 * If using remote paging, then the first load call must specify the <em>start</em>
22995 * and <em>limit</em> properties in the options.params property to establish the initial
22996 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22998 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22999 * and this call will return before the new data has been loaded. Perform any post-processing
23000 * in a callback function, or in a "load" event handler.</strong>
23002 * @param {Object} options An object containing properties which control loading options:<ul>
23003 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23004 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23005 * passed the following arguments:<ul>
23006 * <li>r : Roo.data.Record[]</li>
23007 * <li>options: Options object from the load call</li>
23008 * <li>success: Boolean success indicator</li></ul></li>
23009 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23010 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23013 load : function(options){
23014 options = options || {};
23015 if(this.fireEvent("beforeload", this, options) !== false){
23016 this.storeOptions(options);
23017 var p = Roo.apply(options.params || {}, this.baseParams);
23018 // if meta was not loaded from remote source.. try requesting it.
23019 if (!this.reader.metaFromRemote) {
23020 p._requestMeta = 1;
23022 if(this.sortInfo && this.remoteSort){
23023 var pn = this.paramNames;
23024 p[pn["sort"]] = this.sortInfo.field;
23025 p[pn["dir"]] = this.sortInfo.direction;
23027 if (this.multiSort) {
23028 var pn = this.paramNames;
23029 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23032 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23037 * Reloads the Record cache from the configured Proxy using the configured Reader and
23038 * the options from the last load operation performed.
23039 * @param {Object} options (optional) An object containing properties which may override the options
23040 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23041 * the most recently used options are reused).
23043 reload : function(options){
23044 this.load(Roo.applyIf(options||{}, this.lastOptions));
23048 // Called as a callback by the Reader during a load operation.
23049 loadRecords : function(o, options, success){
23050 if(!o || success === false){
23051 if(success !== false){
23052 this.fireEvent("load", this, [], options, o);
23054 if(options.callback){
23055 options.callback.call(options.scope || this, [], options, false);
23059 // if data returned failure - throw an exception.
23060 if (o.success === false) {
23061 // show a message if no listener is registered.
23062 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23063 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23065 // loadmask wil be hooked into this..
23066 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23069 var r = o.records, t = o.totalRecords || r.length;
23071 this.fireEvent("beforeloadadd", this, r, options, o);
23073 if(!options || options.add !== true){
23074 if(this.pruneModifiedRecords){
23075 this.modified = [];
23077 for(var i = 0, len = r.length; i < len; i++){
23081 this.data = this.snapshot;
23082 delete this.snapshot;
23085 this.data.addAll(r);
23086 this.totalLength = t;
23088 this.fireEvent("datachanged", this);
23090 this.totalLength = Math.max(t, this.data.length+r.length);
23094 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23096 var e = new Roo.data.Record({});
23098 e.set(this.parent.displayField, this.parent.emptyTitle);
23099 e.set(this.parent.valueField, '');
23104 this.fireEvent("load", this, r, options, o);
23105 if(options.callback){
23106 options.callback.call(options.scope || this, r, options, true);
23112 * Loads data from a passed data block. A Reader which understands the format of the data
23113 * must have been configured in the constructor.
23114 * @param {Object} data The data block from which to read the Records. The format of the data expected
23115 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23116 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23118 loadData : function(o, append){
23119 var r = this.reader.readRecords(o);
23120 this.loadRecords(r, {add: append}, true);
23124 * Gets the number of cached records.
23126 * <em>If using paging, this may not be the total size of the dataset. If the data object
23127 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23128 * the data set size</em>
23130 getCount : function(){
23131 return this.data.length || 0;
23135 * Gets the total number of records in the dataset as returned by the server.
23137 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23138 * the dataset size</em>
23140 getTotalCount : function(){
23141 return this.totalLength || 0;
23145 * Returns the sort state of the Store as an object with two properties:
23147 field {String} The name of the field by which the Records are sorted
23148 direction {String} The sort order, "ASC" or "DESC"
23151 getSortState : function(){
23152 return this.sortInfo;
23156 applySort : function(){
23157 if(this.sortInfo && !this.remoteSort){
23158 var s = this.sortInfo, f = s.field;
23159 var st = this.fields.get(f).sortType;
23160 var fn = function(r1, r2){
23161 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23162 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23164 this.data.sort(s.direction, fn);
23165 if(this.snapshot && this.snapshot != this.data){
23166 this.snapshot.sort(s.direction, fn);
23172 * Sets the default sort column and order to be used by the next load operation.
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 setDefaultSort : function(field, dir){
23177 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23181 * Sort the Records.
23182 * If remote sorting is used, the sort is performed on the server, and the cache is
23183 * reloaded. If local sorting is used, the cache is sorted internally.
23184 * @param {String} fieldName The name of the field to sort by.
23185 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23187 sort : function(fieldName, dir){
23188 var f = this.fields.get(fieldName);
23190 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23192 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23193 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23198 this.sortToggle[f.name] = dir;
23199 this.sortInfo = {field: f.name, direction: dir};
23200 if(!this.remoteSort){
23202 this.fireEvent("datachanged", this);
23204 this.load(this.lastOptions);
23209 * Calls the specified function for each of the Records in the cache.
23210 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23211 * Returning <em>false</em> aborts and exits the iteration.
23212 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23214 each : function(fn, scope){
23215 this.data.each(fn, scope);
23219 * Gets all records modified since the last commit. Modified records are persisted across load operations
23220 * (e.g., during paging).
23221 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23223 getModifiedRecords : function(){
23224 return this.modified;
23228 createFilterFn : function(property, value, anyMatch){
23229 if(!value.exec){ // not a regex
23230 value = String(value);
23231 if(value.length == 0){
23234 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23236 return function(r){
23237 return value.test(r.data[property]);
23242 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23243 * @param {String} property A field on your records
23244 * @param {Number} start The record index to start at (defaults to 0)
23245 * @param {Number} end The last record index to include (defaults to length - 1)
23246 * @return {Number} The sum
23248 sum : function(property, start, end){
23249 var rs = this.data.items, v = 0;
23250 start = start || 0;
23251 end = (end || end === 0) ? end : rs.length-1;
23253 for(var i = start; i <= end; i++){
23254 v += (rs[i].data[property] || 0);
23260 * Filter the records by a specified property.
23261 * @param {String} field A field on your records
23262 * @param {String/RegExp} value Either a string that the field
23263 * should start with or a RegExp to test against the field
23264 * @param {Boolean} anyMatch True to match any part not just the beginning
23266 filter : function(property, value, anyMatch){
23267 var fn = this.createFilterFn(property, value, anyMatch);
23268 return fn ? this.filterBy(fn) : this.clearFilter();
23272 * Filter by a function. The specified function will be called with each
23273 * record in this data source. If the function returns true the record is included,
23274 * otherwise it is filtered.
23275 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23276 * @param {Object} scope (optional) The scope of the function (defaults to this)
23278 filterBy : function(fn, scope){
23279 this.snapshot = this.snapshot || this.data;
23280 this.data = this.queryBy(fn, scope||this);
23281 this.fireEvent("datachanged", this);
23285 * Query the records by a specified property.
23286 * @param {String} field A field on your records
23287 * @param {String/RegExp} value Either a string that the field
23288 * should start with or a RegExp to test against the field
23289 * @param {Boolean} anyMatch True to match any part not just the beginning
23290 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23292 query : function(property, value, anyMatch){
23293 var fn = this.createFilterFn(property, value, anyMatch);
23294 return fn ? this.queryBy(fn) : this.data.clone();
23298 * Query by a function. The specified function will be called with each
23299 * record in this data source. If the function returns true the record is included
23301 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23302 * @param {Object} scope (optional) The scope of the function (defaults to this)
23303 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23305 queryBy : function(fn, scope){
23306 var data = this.snapshot || this.data;
23307 return data.filterBy(fn, scope||this);
23311 * Collects unique values for a particular dataIndex from this store.
23312 * @param {String} dataIndex The property to collect
23313 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23314 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23315 * @return {Array} An array of the unique values
23317 collect : function(dataIndex, allowNull, bypassFilter){
23318 var d = (bypassFilter === true && this.snapshot) ?
23319 this.snapshot.items : this.data.items;
23320 var v, sv, r = [], l = {};
23321 for(var i = 0, len = d.length; i < len; i++){
23322 v = d[i].data[dataIndex];
23324 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23333 * Revert to a view of the Record cache with no filtering applied.
23334 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23336 clearFilter : function(suppressEvent){
23337 if(this.snapshot && this.snapshot != this.data){
23338 this.data = this.snapshot;
23339 delete this.snapshot;
23340 if(suppressEvent !== true){
23341 this.fireEvent("datachanged", this);
23347 afterEdit : function(record){
23348 if(this.modified.indexOf(record) == -1){
23349 this.modified.push(record);
23351 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23355 afterReject : function(record){
23356 this.modified.remove(record);
23357 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23361 afterCommit : function(record){
23362 this.modified.remove(record);
23363 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23367 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23368 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23370 commitChanges : function(){
23371 var m = this.modified.slice(0);
23372 this.modified = [];
23373 for(var i = 0, len = m.length; i < len; i++){
23379 * Cancel outstanding changes on all changed records.
23381 rejectChanges : function(){
23382 var m = this.modified.slice(0);
23383 this.modified = [];
23384 for(var i = 0, len = m.length; i < len; i++){
23389 onMetaChange : function(meta, rtype, o){
23390 this.recordType = rtype;
23391 this.fields = rtype.prototype.fields;
23392 delete this.snapshot;
23393 this.sortInfo = meta.sortInfo || this.sortInfo;
23394 this.modified = [];
23395 this.fireEvent('metachange', this, this.reader.meta);
23398 moveIndex : function(data, type)
23400 var index = this.indexOf(data);
23402 var newIndex = index + type;
23406 this.insert(newIndex, data);
23411 * Ext JS Library 1.1.1
23412 * Copyright(c) 2006-2007, Ext JS, LLC.
23414 * Originally Released Under LGPL - original licence link has changed is not relivant.
23417 * <script type="text/javascript">
23421 * @class Roo.data.SimpleStore
23422 * @extends Roo.data.Store
23423 * Small helper class to make creating Stores from Array data easier.
23424 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23425 * @cfg {Array} fields An array of field definition objects, or field name strings.
23426 * @cfg {Array} data The multi-dimensional array of data
23428 * @param {Object} config
23430 Roo.data.SimpleStore = function(config){
23431 Roo.data.SimpleStore.superclass.constructor.call(this, {
23433 reader: new Roo.data.ArrayReader({
23436 Roo.data.Record.create(config.fields)
23438 proxy : new Roo.data.MemoryProxy(config.data)
23442 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23444 * Ext JS Library 1.1.1
23445 * Copyright(c) 2006-2007, Ext JS, LLC.
23447 * Originally Released Under LGPL - original licence link has changed is not relivant.
23450 * <script type="text/javascript">
23455 * @extends Roo.data.Store
23456 * @class Roo.data.JsonStore
23457 * Small helper class to make creating Stores for JSON data easier. <br/>
23459 var store = new Roo.data.JsonStore({
23460 url: 'get-images.php',
23462 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23465 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23466 * JsonReader and HttpProxy (unless inline data is provided).</b>
23467 * @cfg {Array} fields An array of field definition objects, or field name strings.
23469 * @param {Object} config
23471 Roo.data.JsonStore = function(c){
23472 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23473 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23474 reader: new Roo.data.JsonReader(c, c.fields)
23477 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23479 * Ext JS Library 1.1.1
23480 * Copyright(c) 2006-2007, Ext JS, LLC.
23482 * Originally Released Under LGPL - original licence link has changed is not relivant.
23485 * <script type="text/javascript">
23489 Roo.data.Field = function(config){
23490 if(typeof config == "string"){
23491 config = {name: config};
23493 Roo.apply(this, config);
23496 this.type = "auto";
23499 var st = Roo.data.SortTypes;
23500 // named sortTypes are supported, here we look them up
23501 if(typeof this.sortType == "string"){
23502 this.sortType = st[this.sortType];
23505 // set default sortType for strings and dates
23506 if(!this.sortType){
23509 this.sortType = st.asUCString;
23512 this.sortType = st.asDate;
23515 this.sortType = st.none;
23520 var stripRe = /[\$,%]/g;
23522 // prebuilt conversion function for this field, instead of
23523 // switching every time we're reading a value
23525 var cv, dateFormat = this.dateFormat;
23530 cv = function(v){ return v; };
23533 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23537 return v !== undefined && v !== null && v !== '' ?
23538 parseInt(String(v).replace(stripRe, ""), 10) : '';
23543 return v !== undefined && v !== null && v !== '' ?
23544 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23549 cv = function(v){ return v === true || v === "true" || v == 1; };
23556 if(v instanceof Date){
23560 if(dateFormat == "timestamp"){
23561 return new Date(v*1000);
23563 return Date.parseDate(v, dateFormat);
23565 var parsed = Date.parse(v);
23566 return parsed ? new Date(parsed) : null;
23575 Roo.data.Field.prototype = {
23583 * Ext JS Library 1.1.1
23584 * Copyright(c) 2006-2007, Ext JS, LLC.
23586 * Originally Released Under LGPL - original licence link has changed is not relivant.
23589 * <script type="text/javascript">
23592 // Base class for reading structured data from a data source. This class is intended to be
23593 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23596 * @class Roo.data.DataReader
23597 * Base class for reading structured data from a data source. This class is intended to be
23598 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23601 Roo.data.DataReader = function(meta, recordType){
23605 this.recordType = recordType instanceof Array ?
23606 Roo.data.Record.create(recordType) : recordType;
23609 Roo.data.DataReader.prototype = {
23611 * Create an empty record
23612 * @param {Object} data (optional) - overlay some values
23613 * @return {Roo.data.Record} record created.
23615 newRow : function(d) {
23617 this.recordType.prototype.fields.each(function(c) {
23619 case 'int' : da[c.name] = 0; break;
23620 case 'date' : da[c.name] = new Date(); break;
23621 case 'float' : da[c.name] = 0.0; break;
23622 case 'boolean' : da[c.name] = false; break;
23623 default : da[c.name] = ""; break;
23627 return new this.recordType(Roo.apply(da, d));
23632 * Ext JS Library 1.1.1
23633 * Copyright(c) 2006-2007, Ext JS, LLC.
23635 * Originally Released Under LGPL - original licence link has changed is not relivant.
23638 * <script type="text/javascript">
23642 * @class Roo.data.DataProxy
23643 * @extends Roo.data.Observable
23644 * This class is an abstract base class for implementations which provide retrieval of
23645 * unformatted data objects.<br>
23647 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23648 * (of the appropriate type which knows how to parse the data object) to provide a block of
23649 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23651 * Custom implementations must implement the load method as described in
23652 * {@link Roo.data.HttpProxy#load}.
23654 Roo.data.DataProxy = function(){
23657 * @event beforeload
23658 * Fires before a network request is made to retrieve a data object.
23659 * @param {Object} This DataProxy object.
23660 * @param {Object} params The params parameter to the load function.
23665 * Fires before the load method's callback is called.
23666 * @param {Object} This DataProxy object.
23667 * @param {Object} o The data object.
23668 * @param {Object} arg The callback argument object passed to the load function.
23672 * @event loadexception
23673 * Fires if an Exception occurs during data retrieval.
23674 * @param {Object} This DataProxy object.
23675 * @param {Object} o The data object.
23676 * @param {Object} arg The callback argument object passed to the load function.
23677 * @param {Object} e The Exception.
23679 loadexception : true
23681 Roo.data.DataProxy.superclass.constructor.call(this);
23684 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23687 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23691 * Ext JS Library 1.1.1
23692 * Copyright(c) 2006-2007, Ext JS, LLC.
23694 * Originally Released Under LGPL - original licence link has changed is not relivant.
23697 * <script type="text/javascript">
23700 * @class Roo.data.MemoryProxy
23701 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23702 * to the Reader when its load method is called.
23704 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23706 Roo.data.MemoryProxy = function(data){
23710 Roo.data.MemoryProxy.superclass.constructor.call(this);
23714 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23717 * Load data from the requested source (in this case an in-memory
23718 * data object passed to the constructor), read the data object into
23719 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23720 * process that block using the passed callback.
23721 * @param {Object} params This parameter is not used by the MemoryProxy class.
23722 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23723 * object into a block of Roo.data.Records.
23724 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23725 * The function must be passed <ul>
23726 * <li>The Record block object</li>
23727 * <li>The "arg" argument from the load function</li>
23728 * <li>A boolean success indicator</li>
23730 * @param {Object} scope The scope in which to call the callback
23731 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23733 load : function(params, reader, callback, scope, arg){
23734 params = params || {};
23737 result = reader.readRecords(this.data);
23739 this.fireEvent("loadexception", this, arg, null, e);
23740 callback.call(scope, null, arg, false);
23743 callback.call(scope, result, arg, true);
23747 update : function(params, records){
23752 * Ext JS Library 1.1.1
23753 * Copyright(c) 2006-2007, Ext JS, LLC.
23755 * Originally Released Under LGPL - original licence link has changed is not relivant.
23758 * <script type="text/javascript">
23761 * @class Roo.data.HttpProxy
23762 * @extends Roo.data.DataProxy
23763 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23764 * configured to reference a certain URL.<br><br>
23766 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23767 * from which the running page was served.<br><br>
23769 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23771 * Be aware that to enable the browser to parse an XML document, the server must set
23772 * the Content-Type header in the HTTP response to "text/xml".
23774 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23775 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23776 * will be used to make the request.
23778 Roo.data.HttpProxy = function(conn){
23779 Roo.data.HttpProxy.superclass.constructor.call(this);
23780 // is conn a conn config or a real conn?
23782 this.useAjax = !conn || !conn.events;
23786 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23787 // thse are take from connection...
23790 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23793 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23794 * extra parameters to each request made by this object. (defaults to undefined)
23797 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23798 * to each request made by this object. (defaults to undefined)
23801 * @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)
23804 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23807 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23813 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23817 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23818 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23819 * a finer-grained basis than the DataProxy events.
23821 getConnection : function(){
23822 return this.useAjax ? Roo.Ajax : this.conn;
23826 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23827 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23828 * process that block using the passed callback.
23829 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23830 * for the request to the remote server.
23831 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23832 * object into a block of Roo.data.Records.
23833 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23834 * The function must be passed <ul>
23835 * <li>The Record block object</li>
23836 * <li>The "arg" argument from the load function</li>
23837 * <li>A boolean success indicator</li>
23839 * @param {Object} scope The scope in which to call the callback
23840 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23842 load : function(params, reader, callback, scope, arg){
23843 if(this.fireEvent("beforeload", this, params) !== false){
23845 params : params || {},
23847 callback : callback,
23852 callback : this.loadResponse,
23856 Roo.applyIf(o, this.conn);
23857 if(this.activeRequest){
23858 Roo.Ajax.abort(this.activeRequest);
23860 this.activeRequest = Roo.Ajax.request(o);
23862 this.conn.request(o);
23865 callback.call(scope||this, null, arg, false);
23870 loadResponse : function(o, success, response){
23871 delete this.activeRequest;
23873 this.fireEvent("loadexception", this, o, response);
23874 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23879 result = o.reader.read(response);
23881 this.fireEvent("loadexception", this, o, response, e);
23882 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23886 this.fireEvent("load", this, o, o.request.arg);
23887 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23891 update : function(dataSet){
23896 updateResponse : function(dataSet){
23901 * Ext JS Library 1.1.1
23902 * Copyright(c) 2006-2007, Ext JS, LLC.
23904 * Originally Released Under LGPL - original licence link has changed is not relivant.
23907 * <script type="text/javascript">
23911 * @class Roo.data.ScriptTagProxy
23912 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23913 * other than the originating domain of the running page.<br><br>
23915 * <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
23916 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23918 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23919 * source code that is used as the source inside a <script> tag.<br><br>
23921 * In order for the browser to process the returned data, the server must wrap the data object
23922 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23923 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23924 * depending on whether the callback name was passed:
23927 boolean scriptTag = false;
23928 String cb = request.getParameter("callback");
23931 response.setContentType("text/javascript");
23933 response.setContentType("application/x-json");
23935 Writer out = response.getWriter();
23937 out.write(cb + "(");
23939 out.print(dataBlock.toJsonString());
23946 * @param {Object} config A configuration object.
23948 Roo.data.ScriptTagProxy = function(config){
23949 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23950 Roo.apply(this, config);
23951 this.head = document.getElementsByTagName("head")[0];
23954 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23956 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23958 * @cfg {String} url The URL from which to request the data object.
23961 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23965 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23966 * the server the name of the callback function set up by the load call to process the returned data object.
23967 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23968 * javascript output which calls this named function passing the data object as its only parameter.
23970 callbackParam : "callback",
23972 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23973 * name to the request.
23978 * Load data from the configured URL, read the data object into
23979 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23980 * process that block using the passed callback.
23981 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23982 * for the request to the remote server.
23983 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23984 * object into a block of Roo.data.Records.
23985 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23986 * The function must be passed <ul>
23987 * <li>The Record block object</li>
23988 * <li>The "arg" argument from the load function</li>
23989 * <li>A boolean success indicator</li>
23991 * @param {Object} scope The scope in which to call the callback
23992 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23994 load : function(params, reader, callback, scope, arg){
23995 if(this.fireEvent("beforeload", this, params) !== false){
23997 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23999 var url = this.url;
24000 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24002 url += "&_dc=" + (new Date().getTime());
24004 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24007 cb : "stcCallback"+transId,
24008 scriptId : "stcScript"+transId,
24012 callback : callback,
24018 window[trans.cb] = function(o){
24019 conn.handleResponse(o, trans);
24022 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24024 if(this.autoAbort !== false){
24028 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24030 var script = document.createElement("script");
24031 script.setAttribute("src", url);
24032 script.setAttribute("type", "text/javascript");
24033 script.setAttribute("id", trans.scriptId);
24034 this.head.appendChild(script);
24036 this.trans = trans;
24038 callback.call(scope||this, null, arg, false);
24043 isLoading : function(){
24044 return this.trans ? true : false;
24048 * Abort the current server request.
24050 abort : function(){
24051 if(this.isLoading()){
24052 this.destroyTrans(this.trans);
24057 destroyTrans : function(trans, isLoaded){
24058 this.head.removeChild(document.getElementById(trans.scriptId));
24059 clearTimeout(trans.timeoutId);
24061 window[trans.cb] = undefined;
24063 delete window[trans.cb];
24066 // if hasn't been loaded, wait for load to remove it to prevent script error
24067 window[trans.cb] = function(){
24068 window[trans.cb] = undefined;
24070 delete window[trans.cb];
24077 handleResponse : function(o, trans){
24078 this.trans = false;
24079 this.destroyTrans(trans, true);
24082 result = trans.reader.readRecords(o);
24084 this.fireEvent("loadexception", this, o, trans.arg, e);
24085 trans.callback.call(trans.scope||window, null, trans.arg, false);
24088 this.fireEvent("load", this, o, trans.arg);
24089 trans.callback.call(trans.scope||window, result, trans.arg, true);
24093 handleFailure : function(trans){
24094 this.trans = false;
24095 this.destroyTrans(trans, false);
24096 this.fireEvent("loadexception", this, null, trans.arg);
24097 trans.callback.call(trans.scope||window, null, trans.arg, false);
24101 * Ext JS Library 1.1.1
24102 * Copyright(c) 2006-2007, Ext JS, LLC.
24104 * Originally Released Under LGPL - original licence link has changed is not relivant.
24107 * <script type="text/javascript">
24111 * @class Roo.data.JsonReader
24112 * @extends Roo.data.DataReader
24113 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24114 * based on mappings in a provided Roo.data.Record constructor.
24116 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24117 * in the reply previously.
24122 var RecordDef = Roo.data.Record.create([
24123 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24124 {name: 'occupation'} // This field will use "occupation" as the mapping.
24126 var myReader = new Roo.data.JsonReader({
24127 totalProperty: "results", // The property which contains the total dataset size (optional)
24128 root: "rows", // The property which contains an Array of row objects
24129 id: "id" // The property within each row object that provides an ID for the record (optional)
24133 * This would consume a JSON file like this:
24135 { 'results': 2, 'rows': [
24136 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24137 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24140 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24141 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24142 * paged from the remote server.
24143 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24144 * @cfg {String} root name of the property which contains the Array of row objects.
24145 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24146 * @cfg {Array} fields Array of field definition objects
24148 * Create a new JsonReader
24149 * @param {Object} meta Metadata configuration options
24150 * @param {Object} recordType Either an Array of field definition objects,
24151 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24153 Roo.data.JsonReader = function(meta, recordType){
24156 // set some defaults:
24157 Roo.applyIf(meta, {
24158 totalProperty: 'total',
24159 successProperty : 'success',
24164 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24166 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24169 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24170 * Used by Store query builder to append _requestMeta to params.
24173 metaFromRemote : false,
24175 * This method is only used by a DataProxy which has retrieved data from a remote server.
24176 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24177 * @return {Object} data A data block which is used by an Roo.data.Store object as
24178 * a cache of Roo.data.Records.
24180 read : function(response){
24181 var json = response.responseText;
24183 var o = /* eval:var:o */ eval("("+json+")");
24185 throw {message: "JsonReader.read: Json object not found"};
24191 this.metaFromRemote = true;
24192 this.meta = o.metaData;
24193 this.recordType = Roo.data.Record.create(o.metaData.fields);
24194 this.onMetaChange(this.meta, this.recordType, o);
24196 return this.readRecords(o);
24199 // private function a store will implement
24200 onMetaChange : function(meta, recordType, o){
24207 simpleAccess: function(obj, subsc) {
24214 getJsonAccessor: function(){
24216 return function(expr) {
24218 return(re.test(expr))
24219 ? new Function("obj", "return obj." + expr)
24224 return Roo.emptyFn;
24229 * Create a data block containing Roo.data.Records from an XML document.
24230 * @param {Object} o An object which contains an Array of row objects in the property specified
24231 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24232 * which contains the total size of the dataset.
24233 * @return {Object} data A data block which is used by an Roo.data.Store object as
24234 * a cache of Roo.data.Records.
24236 readRecords : function(o){
24238 * After any data loads, the raw JSON data is available for further custom processing.
24242 var s = this.meta, Record = this.recordType,
24243 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24245 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24247 if(s.totalProperty) {
24248 this.getTotal = this.getJsonAccessor(s.totalProperty);
24250 if(s.successProperty) {
24251 this.getSuccess = this.getJsonAccessor(s.successProperty);
24253 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24255 var g = this.getJsonAccessor(s.id);
24256 this.getId = function(rec) {
24258 return (r === undefined || r === "") ? null : r;
24261 this.getId = function(){return null;};
24264 for(var jj = 0; jj < fl; jj++){
24266 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24267 this.ef[jj] = this.getJsonAccessor(map);
24271 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24272 if(s.totalProperty){
24273 var vt = parseInt(this.getTotal(o), 10);
24278 if(s.successProperty){
24279 var vs = this.getSuccess(o);
24280 if(vs === false || vs === 'false'){
24285 for(var i = 0; i < c; i++){
24288 var id = this.getId(n);
24289 for(var j = 0; j < fl; j++){
24291 var v = this.ef[j](n);
24293 Roo.log('missing convert for ' + f.name);
24297 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24299 var record = new Record(values, id);
24301 records[i] = record;
24307 totalRecords : totalRecords
24312 * Ext JS Library 1.1.1
24313 * Copyright(c) 2006-2007, Ext JS, LLC.
24315 * Originally Released Under LGPL - original licence link has changed is not relivant.
24318 * <script type="text/javascript">
24322 * @class Roo.data.XmlReader
24323 * @extends Roo.data.DataReader
24324 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24325 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24327 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24328 * header in the HTTP response must be set to "text/xml".</em>
24332 var RecordDef = Roo.data.Record.create([
24333 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24334 {name: 'occupation'} // This field will use "occupation" as the mapping.
24336 var myReader = new Roo.data.XmlReader({
24337 totalRecords: "results", // The element which contains the total dataset size (optional)
24338 record: "row", // The repeated element which contains row information
24339 id: "id" // The element within the row that provides an ID for the record (optional)
24343 * This would consume an XML file like this:
24347 <results>2</results>
24350 <name>Bill</name>
24351 <occupation>Gardener</occupation>
24355 <name>Ben</name>
24356 <occupation>Horticulturalist</occupation>
24360 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24361 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24362 * paged from the remote server.
24363 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24364 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24365 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24366 * a record identifier value.
24368 * Create a new XmlReader
24369 * @param {Object} meta Metadata configuration options
24370 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24371 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24372 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24374 Roo.data.XmlReader = function(meta, recordType){
24376 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24378 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24380 * This method is only used by a DataProxy which has retrieved data from a remote server.
24381 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24382 * to contain a method called 'responseXML' that returns an XML document object.
24383 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24384 * a cache of Roo.data.Records.
24386 read : function(response){
24387 var doc = response.responseXML;
24389 throw {message: "XmlReader.read: XML Document not available"};
24391 return this.readRecords(doc);
24395 * Create a data block containing Roo.data.Records from an XML document.
24396 * @param {Object} doc A parsed XML document.
24397 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24398 * a cache of Roo.data.Records.
24400 readRecords : function(doc){
24402 * After any data loads/reads, the raw XML Document is available for further custom processing.
24403 * @type XMLDocument
24405 this.xmlData = doc;
24406 var root = doc.documentElement || doc;
24407 var q = Roo.DomQuery;
24408 var recordType = this.recordType, fields = recordType.prototype.fields;
24409 var sid = this.meta.id;
24410 var totalRecords = 0, success = true;
24411 if(this.meta.totalRecords){
24412 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24415 if(this.meta.success){
24416 var sv = q.selectValue(this.meta.success, root, true);
24417 success = sv !== false && sv !== 'false';
24420 var ns = q.select(this.meta.record, root);
24421 for(var i = 0, len = ns.length; i < len; i++) {
24424 var id = sid ? q.selectValue(sid, n) : undefined;
24425 for(var j = 0, jlen = fields.length; j < jlen; j++){
24426 var f = fields.items[j];
24427 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24429 values[f.name] = v;
24431 var record = new recordType(values, id);
24433 records[records.length] = record;
24439 totalRecords : totalRecords || records.length
24444 * Ext JS Library 1.1.1
24445 * Copyright(c) 2006-2007, Ext JS, LLC.
24447 * Originally Released Under LGPL - original licence link has changed is not relivant.
24450 * <script type="text/javascript">
24454 * @class Roo.data.ArrayReader
24455 * @extends Roo.data.DataReader
24456 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24457 * Each element of that Array represents a row of data fields. The
24458 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24459 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24463 var RecordDef = Roo.data.Record.create([
24464 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24465 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24467 var myReader = new Roo.data.ArrayReader({
24468 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24472 * This would consume an Array like this:
24474 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24476 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24478 * Create a new JsonReader
24479 * @param {Object} meta Metadata configuration options.
24480 * @param {Object} recordType Either an Array of field definition objects
24481 * as specified to {@link Roo.data.Record#create},
24482 * or an {@link Roo.data.Record} object
24483 * created using {@link Roo.data.Record#create}.
24485 Roo.data.ArrayReader = function(meta, recordType){
24486 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24489 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24491 * Create a data block containing Roo.data.Records from an XML document.
24492 * @param {Object} o An Array of row objects which represents the dataset.
24493 * @return {Object} data A data block which is used by an Roo.data.Store object as
24494 * a cache of Roo.data.Records.
24496 readRecords : function(o){
24497 var sid = this.meta ? this.meta.id : null;
24498 var recordType = this.recordType, fields = recordType.prototype.fields;
24501 for(var i = 0; i < root.length; i++){
24504 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24505 for(var j = 0, jlen = fields.length; j < jlen; j++){
24506 var f = fields.items[j];
24507 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24508 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24510 values[f.name] = v;
24512 var record = new recordType(values, id);
24514 records[records.length] = record;
24518 totalRecords : records.length
24523 * Ext JS Library 1.1.1
24524 * Copyright(c) 2006-2007, Ext JS, LLC.
24526 * Originally Released Under LGPL - original licence link has changed is not relivant.
24529 * <script type="text/javascript">
24534 * @class Roo.data.Tree
24535 * @extends Roo.util.Observable
24536 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24537 * in the tree have most standard DOM functionality.
24539 * @param {Node} root (optional) The root node
24541 Roo.data.Tree = function(root){
24542 this.nodeHash = {};
24544 * The root node for this tree
24549 this.setRootNode(root);
24554 * Fires when a new child node is appended to a node in this tree.
24555 * @param {Tree} tree The owner tree
24556 * @param {Node} parent The parent node
24557 * @param {Node} node The newly appended node
24558 * @param {Number} index The index of the newly appended node
24563 * Fires when a child node is removed from a node in this tree.
24564 * @param {Tree} tree The owner tree
24565 * @param {Node} parent The parent node
24566 * @param {Node} node The child node removed
24571 * Fires when a node is moved to a new location in the tree
24572 * @param {Tree} tree The owner tree
24573 * @param {Node} node The node moved
24574 * @param {Node} oldParent The old parent of this node
24575 * @param {Node} newParent The new parent of this node
24576 * @param {Number} index The index it was moved to
24581 * Fires when a new child node is inserted in a node in this tree.
24582 * @param {Tree} tree The owner tree
24583 * @param {Node} parent The parent node
24584 * @param {Node} node The child node inserted
24585 * @param {Node} refNode The child node the node was inserted before
24589 * @event beforeappend
24590 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24591 * @param {Tree} tree The owner tree
24592 * @param {Node} parent The parent node
24593 * @param {Node} node The child node to be appended
24595 "beforeappend" : true,
24597 * @event beforeremove
24598 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24599 * @param {Tree} tree The owner tree
24600 * @param {Node} parent The parent node
24601 * @param {Node} node The child node to be removed
24603 "beforeremove" : true,
24605 * @event beforemove
24606 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24607 * @param {Tree} tree The owner tree
24608 * @param {Node} node The node being moved
24609 * @param {Node} oldParent The parent of the node
24610 * @param {Node} newParent The new parent the node is moving to
24611 * @param {Number} index The index it is being moved to
24613 "beforemove" : true,
24615 * @event beforeinsert
24616 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24617 * @param {Tree} tree The owner tree
24618 * @param {Node} parent The parent node
24619 * @param {Node} node The child node to be inserted
24620 * @param {Node} refNode The child node the node is being inserted before
24622 "beforeinsert" : true
24625 Roo.data.Tree.superclass.constructor.call(this);
24628 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24629 pathSeparator: "/",
24631 proxyNodeEvent : function(){
24632 return this.fireEvent.apply(this, arguments);
24636 * Returns the root node for this tree.
24639 getRootNode : function(){
24644 * Sets the root node for this tree.
24645 * @param {Node} node
24648 setRootNode : function(node){
24650 node.ownerTree = this;
24651 node.isRoot = true;
24652 this.registerNode(node);
24657 * Gets a node in this tree by its id.
24658 * @param {String} id
24661 getNodeById : function(id){
24662 return this.nodeHash[id];
24665 registerNode : function(node){
24666 this.nodeHash[node.id] = node;
24669 unregisterNode : function(node){
24670 delete this.nodeHash[node.id];
24673 toString : function(){
24674 return "[Tree"+(this.id?" "+this.id:"")+"]";
24679 * @class Roo.data.Node
24680 * @extends Roo.util.Observable
24681 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24682 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24684 * @param {Object} attributes The attributes/config for the node
24686 Roo.data.Node = function(attributes){
24688 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24691 this.attributes = attributes || {};
24692 this.leaf = this.attributes.leaf;
24694 * The node id. @type String
24696 this.id = this.attributes.id;
24698 this.id = Roo.id(null, "ynode-");
24699 this.attributes.id = this.id;
24704 * All child nodes of this node. @type Array
24706 this.childNodes = [];
24707 if(!this.childNodes.indexOf){ // indexOf is a must
24708 this.childNodes.indexOf = function(o){
24709 for(var i = 0, len = this.length; i < len; i++){
24718 * The parent node for this node. @type Node
24720 this.parentNode = null;
24722 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24724 this.firstChild = null;
24726 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24728 this.lastChild = null;
24730 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24732 this.previousSibling = null;
24734 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24736 this.nextSibling = null;
24741 * Fires when a new child node is appended
24742 * @param {Tree} tree The owner tree
24743 * @param {Node} this This node
24744 * @param {Node} node The newly appended node
24745 * @param {Number} index The index of the newly appended node
24750 * Fires when a child node is removed
24751 * @param {Tree} tree The owner tree
24752 * @param {Node} this This node
24753 * @param {Node} node The removed node
24758 * Fires when this node is moved to a new location in the tree
24759 * @param {Tree} tree The owner tree
24760 * @param {Node} this This node
24761 * @param {Node} oldParent The old parent of this node
24762 * @param {Node} newParent The new parent of this node
24763 * @param {Number} index The index it was moved to
24768 * Fires when a new child node is inserted.
24769 * @param {Tree} tree The owner tree
24770 * @param {Node} this This node
24771 * @param {Node} node The child node inserted
24772 * @param {Node} refNode The child node the node was inserted before
24776 * @event beforeappend
24777 * Fires before a new child is appended, return false to cancel the append.
24778 * @param {Tree} tree The owner tree
24779 * @param {Node} this This node
24780 * @param {Node} node The child node to be appended
24782 "beforeappend" : true,
24784 * @event beforeremove
24785 * Fires before a child is removed, return false to cancel the remove.
24786 * @param {Tree} tree The owner tree
24787 * @param {Node} this This node
24788 * @param {Node} node The child node to be removed
24790 "beforeremove" : true,
24792 * @event beforemove
24793 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24794 * @param {Tree} tree The owner tree
24795 * @param {Node} this This node
24796 * @param {Node} oldParent The parent of this node
24797 * @param {Node} newParent The new parent this node is moving to
24798 * @param {Number} index The index it is being moved to
24800 "beforemove" : true,
24802 * @event beforeinsert
24803 * Fires before a new child is inserted, return false to cancel the insert.
24804 * @param {Tree} tree The owner tree
24805 * @param {Node} this This node
24806 * @param {Node} node The child node to be inserted
24807 * @param {Node} refNode The child node the node is being inserted before
24809 "beforeinsert" : true
24811 this.listeners = this.attributes.listeners;
24812 Roo.data.Node.superclass.constructor.call(this);
24815 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24816 fireEvent : function(evtName){
24817 // first do standard event for this node
24818 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24821 // then bubble it up to the tree if the event wasn't cancelled
24822 var ot = this.getOwnerTree();
24824 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24832 * Returns true if this node is a leaf
24833 * @return {Boolean}
24835 isLeaf : function(){
24836 return this.leaf === true;
24840 setFirstChild : function(node){
24841 this.firstChild = node;
24845 setLastChild : function(node){
24846 this.lastChild = node;
24851 * Returns true if this node is the last child of its parent
24852 * @return {Boolean}
24854 isLast : function(){
24855 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24859 * Returns true if this node is the first child of its parent
24860 * @return {Boolean}
24862 isFirst : function(){
24863 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24866 hasChildNodes : function(){
24867 return !this.isLeaf() && this.childNodes.length > 0;
24871 * Insert node(s) as the last child node of this node.
24872 * @param {Node/Array} node The node or Array of nodes to append
24873 * @return {Node} The appended node if single append, or null if an array was passed
24875 appendChild : function(node){
24877 if(node instanceof Array){
24879 }else if(arguments.length > 1){
24882 // if passed an array or multiple args do them one by one
24884 for(var i = 0, len = multi.length; i < len; i++) {
24885 this.appendChild(multi[i]);
24888 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24891 var index = this.childNodes.length;
24892 var oldParent = node.parentNode;
24893 // it's a move, make sure we move it cleanly
24895 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24898 oldParent.removeChild(node);
24900 index = this.childNodes.length;
24902 this.setFirstChild(node);
24904 this.childNodes.push(node);
24905 node.parentNode = this;
24906 var ps = this.childNodes[index-1];
24908 node.previousSibling = ps;
24909 ps.nextSibling = node;
24911 node.previousSibling = null;
24913 node.nextSibling = null;
24914 this.setLastChild(node);
24915 node.setOwnerTree(this.getOwnerTree());
24916 this.fireEvent("append", this.ownerTree, this, node, index);
24918 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24925 * Removes a child node from this node.
24926 * @param {Node} node The node to remove
24927 * @return {Node} The removed node
24929 removeChild : function(node){
24930 var index = this.childNodes.indexOf(node);
24934 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24938 // remove it from childNodes collection
24939 this.childNodes.splice(index, 1);
24942 if(node.previousSibling){
24943 node.previousSibling.nextSibling = node.nextSibling;
24945 if(node.nextSibling){
24946 node.nextSibling.previousSibling = node.previousSibling;
24949 // update child refs
24950 if(this.firstChild == node){
24951 this.setFirstChild(node.nextSibling);
24953 if(this.lastChild == node){
24954 this.setLastChild(node.previousSibling);
24957 node.setOwnerTree(null);
24958 // clear any references from the node
24959 node.parentNode = null;
24960 node.previousSibling = null;
24961 node.nextSibling = null;
24962 this.fireEvent("remove", this.ownerTree, this, node);
24967 * Inserts the first node before the second node in this nodes childNodes collection.
24968 * @param {Node} node The node to insert
24969 * @param {Node} refNode The node to insert before (if null the node is appended)
24970 * @return {Node} The inserted node
24972 insertBefore : function(node, refNode){
24973 if(!refNode){ // like standard Dom, refNode can be null for append
24974 return this.appendChild(node);
24977 if(node == refNode){
24981 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24984 var index = this.childNodes.indexOf(refNode);
24985 var oldParent = node.parentNode;
24986 var refIndex = index;
24988 // when moving internally, indexes will change after remove
24989 if(oldParent == this && this.childNodes.indexOf(node) < index){
24993 // it's a move, make sure we move it cleanly
24995 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24998 oldParent.removeChild(node);
25001 this.setFirstChild(node);
25003 this.childNodes.splice(refIndex, 0, node);
25004 node.parentNode = this;
25005 var ps = this.childNodes[refIndex-1];
25007 node.previousSibling = ps;
25008 ps.nextSibling = node;
25010 node.previousSibling = null;
25012 node.nextSibling = refNode;
25013 refNode.previousSibling = node;
25014 node.setOwnerTree(this.getOwnerTree());
25015 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25017 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25023 * Returns the child node at the specified index.
25024 * @param {Number} index
25027 item : function(index){
25028 return this.childNodes[index];
25032 * Replaces one child node in this node with another.
25033 * @param {Node} newChild The replacement node
25034 * @param {Node} oldChild The node to replace
25035 * @return {Node} The replaced node
25037 replaceChild : function(newChild, oldChild){
25038 this.insertBefore(newChild, oldChild);
25039 this.removeChild(oldChild);
25044 * Returns the index of a child node
25045 * @param {Node} node
25046 * @return {Number} The index of the node or -1 if it was not found
25048 indexOf : function(child){
25049 return this.childNodes.indexOf(child);
25053 * Returns the tree this node is in.
25056 getOwnerTree : function(){
25057 // if it doesn't have one, look for one
25058 if(!this.ownerTree){
25062 this.ownerTree = p.ownerTree;
25068 return this.ownerTree;
25072 * Returns depth of this node (the root node has a depth of 0)
25075 getDepth : function(){
25078 while(p.parentNode){
25086 setOwnerTree : function(tree){
25087 // if it's move, we need to update everyone
25088 if(tree != this.ownerTree){
25089 if(this.ownerTree){
25090 this.ownerTree.unregisterNode(this);
25092 this.ownerTree = tree;
25093 var cs = this.childNodes;
25094 for(var i = 0, len = cs.length; i < len; i++) {
25095 cs[i].setOwnerTree(tree);
25098 tree.registerNode(this);
25104 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25105 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25106 * @return {String} The path
25108 getPath : function(attr){
25109 attr = attr || "id";
25110 var p = this.parentNode;
25111 var b = [this.attributes[attr]];
25113 b.unshift(p.attributes[attr]);
25116 var sep = this.getOwnerTree().pathSeparator;
25117 return sep + b.join(sep);
25121 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25122 * function call will be the scope provided or the current node. The arguments to the function
25123 * will be the args provided or the current node. If the function returns false at any point,
25124 * the bubble is stopped.
25125 * @param {Function} fn The function to call
25126 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25127 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25129 bubble : function(fn, scope, args){
25132 if(fn.call(scope || p, args || p) === false){
25140 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25141 * function call will be the scope provided or the current node. The arguments to the function
25142 * will be the args provided or the current node. If the function returns false at any point,
25143 * the cascade is stopped on that branch.
25144 * @param {Function} fn The function to call
25145 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25146 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25148 cascade : function(fn, scope, args){
25149 if(fn.call(scope || this, args || this) !== false){
25150 var cs = this.childNodes;
25151 for(var i = 0, len = cs.length; i < len; i++) {
25152 cs[i].cascade(fn, scope, args);
25158 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25159 * function call will be the scope provided or the current node. The arguments to the function
25160 * will be the args provided or the current node. If the function returns false at any point,
25161 * the iteration stops.
25162 * @param {Function} fn The function to call
25163 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25164 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25166 eachChild : function(fn, scope, args){
25167 var cs = this.childNodes;
25168 for(var i = 0, len = cs.length; i < len; i++) {
25169 if(fn.call(scope || this, args || cs[i]) === false){
25176 * Finds the first child that has the attribute with the specified value.
25177 * @param {String} attribute The attribute name
25178 * @param {Mixed} value The value to search for
25179 * @return {Node} The found child or null if none was found
25181 findChild : function(attribute, value){
25182 var cs = this.childNodes;
25183 for(var i = 0, len = cs.length; i < len; i++) {
25184 if(cs[i].attributes[attribute] == value){
25192 * Finds the first child by a custom function. The child matches if the function passed
25194 * @param {Function} fn
25195 * @param {Object} scope (optional)
25196 * @return {Node} The found child or null if none was found
25198 findChildBy : function(fn, scope){
25199 var cs = this.childNodes;
25200 for(var i = 0, len = cs.length; i < len; i++) {
25201 if(fn.call(scope||cs[i], cs[i]) === true){
25209 * Sorts this nodes children using the supplied sort function
25210 * @param {Function} fn
25211 * @param {Object} scope (optional)
25213 sort : function(fn, scope){
25214 var cs = this.childNodes;
25215 var len = cs.length;
25217 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25219 for(var i = 0; i < len; i++){
25221 n.previousSibling = cs[i-1];
25222 n.nextSibling = cs[i+1];
25224 this.setFirstChild(n);
25227 this.setLastChild(n);
25234 * Returns true if this node is an ancestor (at any point) of the passed node.
25235 * @param {Node} node
25236 * @return {Boolean}
25238 contains : function(node){
25239 return node.isAncestor(this);
25243 * Returns true if the passed node is an ancestor (at any point) of this node.
25244 * @param {Node} node
25245 * @return {Boolean}
25247 isAncestor : function(node){
25248 var p = this.parentNode;
25258 toString : function(){
25259 return "[Node"+(this.id?" "+this.id:"")+"]";
25263 * Ext JS Library 1.1.1
25264 * Copyright(c) 2006-2007, Ext JS, LLC.
25266 * Originally Released Under LGPL - original licence link has changed is not relivant.
25269 * <script type="text/javascript">
25274 * @extends Roo.Element
25275 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25276 * automatic maintaining of shadow/shim positions.
25277 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25278 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25279 * you can pass a string with a CSS class name. False turns off the shadow.
25280 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25281 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25282 * @cfg {String} cls CSS class to add to the element
25283 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25284 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25286 * @param {Object} config An object with config options.
25287 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25290 Roo.Layer = function(config, existingEl){
25291 config = config || {};
25292 var dh = Roo.DomHelper;
25293 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25295 this.dom = Roo.getDom(existingEl);
25298 var o = config.dh || {tag: "div", cls: "x-layer"};
25299 this.dom = dh.append(pel, o);
25302 this.addClass(config.cls);
25304 this.constrain = config.constrain !== false;
25305 this.visibilityMode = Roo.Element.VISIBILITY;
25307 this.id = this.dom.id = config.id;
25309 this.id = Roo.id(this.dom);
25311 this.zindex = config.zindex || this.getZIndex();
25312 this.position("absolute", this.zindex);
25314 this.shadowOffset = config.shadowOffset || 4;
25315 this.shadow = new Roo.Shadow({
25316 offset : this.shadowOffset,
25317 mode : config.shadow
25320 this.shadowOffset = 0;
25322 this.useShim = config.shim !== false && Roo.useShims;
25323 this.useDisplay = config.useDisplay;
25327 var supr = Roo.Element.prototype;
25329 // shims are shared among layer to keep from having 100 iframes
25332 Roo.extend(Roo.Layer, Roo.Element, {
25334 getZIndex : function(){
25335 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25338 getShim : function(){
25345 var shim = shims.shift();
25347 shim = this.createShim();
25348 shim.enableDisplayMode('block');
25349 shim.dom.style.display = 'none';
25350 shim.dom.style.visibility = 'visible';
25352 var pn = this.dom.parentNode;
25353 if(shim.dom.parentNode != pn){
25354 pn.insertBefore(shim.dom, this.dom);
25356 shim.setStyle('z-index', this.getZIndex()-2);
25361 hideShim : function(){
25363 this.shim.setDisplayed(false);
25364 shims.push(this.shim);
25369 disableShadow : function(){
25371 this.shadowDisabled = true;
25372 this.shadow.hide();
25373 this.lastShadowOffset = this.shadowOffset;
25374 this.shadowOffset = 0;
25378 enableShadow : function(show){
25380 this.shadowDisabled = false;
25381 this.shadowOffset = this.lastShadowOffset;
25382 delete this.lastShadowOffset;
25390 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25391 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25392 sync : function(doShow){
25393 var sw = this.shadow;
25394 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25395 var sh = this.getShim();
25397 var w = this.getWidth(),
25398 h = this.getHeight();
25400 var l = this.getLeft(true),
25401 t = this.getTop(true);
25403 if(sw && !this.shadowDisabled){
25404 if(doShow && !sw.isVisible()){
25407 sw.realign(l, t, w, h);
25413 // fit the shim behind the shadow, so it is shimmed too
25414 var a = sw.adjusts, s = sh.dom.style;
25415 s.left = (Math.min(l, l+a.l))+"px";
25416 s.top = (Math.min(t, t+a.t))+"px";
25417 s.width = (w+a.w)+"px";
25418 s.height = (h+a.h)+"px";
25425 sh.setLeftTop(l, t);
25432 destroy : function(){
25435 this.shadow.hide();
25437 this.removeAllListeners();
25438 var pn = this.dom.parentNode;
25440 pn.removeChild(this.dom);
25442 Roo.Element.uncache(this.id);
25445 remove : function(){
25450 beginUpdate : function(){
25451 this.updating = true;
25455 endUpdate : function(){
25456 this.updating = false;
25461 hideUnders : function(negOffset){
25463 this.shadow.hide();
25469 constrainXY : function(){
25470 if(this.constrain){
25471 var vw = Roo.lib.Dom.getViewWidth(),
25472 vh = Roo.lib.Dom.getViewHeight();
25473 var s = Roo.get(document).getScroll();
25475 var xy = this.getXY();
25476 var x = xy[0], y = xy[1];
25477 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25478 // only move it if it needs it
25480 // first validate right/bottom
25481 if((x + w) > vw+s.left){
25482 x = vw - w - this.shadowOffset;
25485 if((y + h) > vh+s.top){
25486 y = vh - h - this.shadowOffset;
25489 // then make sure top/left isn't negative
25500 var ay = this.avoidY;
25501 if(y <= ay && (y+h) >= ay){
25507 supr.setXY.call(this, xy);
25513 isVisible : function(){
25514 return this.visible;
25518 showAction : function(){
25519 this.visible = true; // track visibility to prevent getStyle calls
25520 if(this.useDisplay === true){
25521 this.setDisplayed("");
25522 }else if(this.lastXY){
25523 supr.setXY.call(this, this.lastXY);
25524 }else if(this.lastLT){
25525 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25530 hideAction : function(){
25531 this.visible = false;
25532 if(this.useDisplay === true){
25533 this.setDisplayed(false);
25535 this.setLeftTop(-10000,-10000);
25539 // overridden Element method
25540 setVisible : function(v, a, d, c, e){
25545 var cb = function(){
25550 }.createDelegate(this);
25551 supr.setVisible.call(this, true, true, d, cb, e);
25554 this.hideUnders(true);
25563 }.createDelegate(this);
25565 supr.setVisible.call(this, v, a, d, cb, e);
25574 storeXY : function(xy){
25575 delete this.lastLT;
25579 storeLeftTop : function(left, top){
25580 delete this.lastXY;
25581 this.lastLT = [left, top];
25585 beforeFx : function(){
25586 this.beforeAction();
25587 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25591 afterFx : function(){
25592 Roo.Layer.superclass.afterFx.apply(this, arguments);
25593 this.sync(this.isVisible());
25597 beforeAction : function(){
25598 if(!this.updating && this.shadow){
25599 this.shadow.hide();
25603 // overridden Element method
25604 setLeft : function(left){
25605 this.storeLeftTop(left, this.getTop(true));
25606 supr.setLeft.apply(this, arguments);
25610 setTop : function(top){
25611 this.storeLeftTop(this.getLeft(true), top);
25612 supr.setTop.apply(this, arguments);
25616 setLeftTop : function(left, top){
25617 this.storeLeftTop(left, top);
25618 supr.setLeftTop.apply(this, arguments);
25622 setXY : function(xy, a, d, c, e){
25624 this.beforeAction();
25626 var cb = this.createCB(c);
25627 supr.setXY.call(this, xy, a, d, cb, e);
25634 createCB : function(c){
25645 // overridden Element method
25646 setX : function(x, a, d, c, e){
25647 this.setXY([x, this.getY()], a, d, c, e);
25650 // overridden Element method
25651 setY : function(y, a, d, c, e){
25652 this.setXY([this.getX(), y], a, d, c, e);
25655 // overridden Element method
25656 setSize : function(w, h, a, d, c, e){
25657 this.beforeAction();
25658 var cb = this.createCB(c);
25659 supr.setSize.call(this, w, h, a, d, cb, e);
25665 // overridden Element method
25666 setWidth : function(w, a, d, c, e){
25667 this.beforeAction();
25668 var cb = this.createCB(c);
25669 supr.setWidth.call(this, w, a, d, cb, e);
25675 // overridden Element method
25676 setHeight : function(h, a, d, c, e){
25677 this.beforeAction();
25678 var cb = this.createCB(c);
25679 supr.setHeight.call(this, h, a, d, cb, e);
25685 // overridden Element method
25686 setBounds : function(x, y, w, h, a, d, c, e){
25687 this.beforeAction();
25688 var cb = this.createCB(c);
25690 this.storeXY([x, y]);
25691 supr.setXY.call(this, [x, y]);
25692 supr.setSize.call(this, w, h, a, d, cb, e);
25695 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25701 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25702 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25703 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25704 * @param {Number} zindex The new z-index to set
25705 * @return {this} The Layer
25707 setZIndex : function(zindex){
25708 this.zindex = zindex;
25709 this.setStyle("z-index", zindex + 2);
25711 this.shadow.setZIndex(zindex + 1);
25714 this.shim.setStyle("z-index", zindex);
25720 * Ext JS Library 1.1.1
25721 * Copyright(c) 2006-2007, Ext JS, LLC.
25723 * Originally Released Under LGPL - original licence link has changed is not relivant.
25726 * <script type="text/javascript">
25731 * @class Roo.Shadow
25732 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25733 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25734 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25736 * Create a new Shadow
25737 * @param {Object} config The config object
25739 Roo.Shadow = function(config){
25740 Roo.apply(this, config);
25741 if(typeof this.mode != "string"){
25742 this.mode = this.defaultMode;
25744 var o = this.offset, a = {h: 0};
25745 var rad = Math.floor(this.offset/2);
25746 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25752 a.l -= this.offset + rad;
25753 a.t -= this.offset + rad;
25764 a.l -= (this.offset - rad);
25765 a.t -= this.offset + rad;
25767 a.w -= (this.offset - rad)*2;
25778 a.l -= (this.offset - rad);
25779 a.t -= (this.offset - rad);
25781 a.w -= (this.offset + rad + 1);
25782 a.h -= (this.offset + rad);
25791 Roo.Shadow.prototype = {
25793 * @cfg {String} mode
25794 * The shadow display mode. Supports the following options:<br />
25795 * sides: Shadow displays on both sides and bottom only<br />
25796 * frame: Shadow displays equally on all four sides<br />
25797 * drop: Traditional bottom-right drop shadow (default)
25800 * @cfg {String} offset
25801 * The number of pixels to offset the shadow from the element (defaults to 4)
25806 defaultMode: "drop",
25809 * Displays the shadow under the target element
25810 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25812 show : function(target){
25813 target = Roo.get(target);
25815 this.el = Roo.Shadow.Pool.pull();
25816 if(this.el.dom.nextSibling != target.dom){
25817 this.el.insertBefore(target);
25820 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25822 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25825 target.getLeft(true),
25826 target.getTop(true),
25830 this.el.dom.style.display = "block";
25834 * Returns true if the shadow is visible, else false
25836 isVisible : function(){
25837 return this.el ? true : false;
25841 * Direct alignment when values are already available. Show must be called at least once before
25842 * calling this method to ensure it is initialized.
25843 * @param {Number} left The target element left position
25844 * @param {Number} top The target element top position
25845 * @param {Number} width The target element width
25846 * @param {Number} height The target element height
25848 realign : function(l, t, w, h){
25852 var a = this.adjusts, d = this.el.dom, s = d.style;
25854 s.left = (l+a.l)+"px";
25855 s.top = (t+a.t)+"px";
25856 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25858 if(s.width != sws || s.height != shs){
25862 var cn = d.childNodes;
25863 var sww = Math.max(0, (sw-12))+"px";
25864 cn[0].childNodes[1].style.width = sww;
25865 cn[1].childNodes[1].style.width = sww;
25866 cn[2].childNodes[1].style.width = sww;
25867 cn[1].style.height = Math.max(0, (sh-12))+"px";
25873 * Hides this shadow
25877 this.el.dom.style.display = "none";
25878 Roo.Shadow.Pool.push(this.el);
25884 * Adjust the z-index of this shadow
25885 * @param {Number} zindex The new z-index
25887 setZIndex : function(z){
25890 this.el.setStyle("z-index", z);
25895 // Private utility class that manages the internal Shadow cache
25896 Roo.Shadow.Pool = function(){
25898 var markup = Roo.isIE ?
25899 '<div class="x-ie-shadow"></div>' :
25900 '<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>';
25903 var sh = p.shift();
25905 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25906 sh.autoBoxAdjust = false;
25911 push : function(sh){
25917 * Ext JS Library 1.1.1
25918 * Copyright(c) 2006-2007, Ext JS, LLC.
25920 * Originally Released Under LGPL - original licence link has changed is not relivant.
25923 * <script type="text/javascript">
25928 * @class Roo.SplitBar
25929 * @extends Roo.util.Observable
25930 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25934 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25935 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25936 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25937 split.minSize = 100;
25938 split.maxSize = 600;
25939 split.animate = true;
25940 split.on('moved', splitterMoved);
25943 * Create a new SplitBar
25944 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25945 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25946 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25947 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25948 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25949 position of the SplitBar).
25951 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25954 this.el = Roo.get(dragElement, true);
25955 this.el.dom.unselectable = "on";
25957 this.resizingEl = Roo.get(resizingElement, true);
25961 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25962 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25965 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25968 * The minimum size of the resizing element. (Defaults to 0)
25974 * The maximum size of the resizing element. (Defaults to 2000)
25977 this.maxSize = 2000;
25980 * Whether to animate the transition to the new size
25983 this.animate = false;
25986 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25989 this.useShim = false;
25994 if(!existingProxy){
25996 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25998 this.proxy = Roo.get(existingProxy).dom;
26001 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26004 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26007 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26010 this.dragSpecs = {};
26013 * @private The adapter to use to positon and resize elements
26015 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26016 this.adapter.init(this);
26018 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26020 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26021 this.el.addClass("x-splitbar-h");
26024 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26025 this.el.addClass("x-splitbar-v");
26031 * Fires when the splitter is moved (alias for {@link #event-moved})
26032 * @param {Roo.SplitBar} this
26033 * @param {Number} newSize the new width or height
26038 * Fires when the splitter is moved
26039 * @param {Roo.SplitBar} this
26040 * @param {Number} newSize the new width or height
26044 * @event beforeresize
26045 * Fires before the splitter is dragged
26046 * @param {Roo.SplitBar} this
26048 "beforeresize" : true,
26050 "beforeapply" : true
26053 Roo.util.Observable.call(this);
26056 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26057 onStartProxyDrag : function(x, y){
26058 this.fireEvent("beforeresize", this);
26060 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26062 o.enableDisplayMode("block");
26063 // all splitbars share the same overlay
26064 Roo.SplitBar.prototype.overlay = o;
26066 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26067 this.overlay.show();
26068 Roo.get(this.proxy).setDisplayed("block");
26069 var size = this.adapter.getElementSize(this);
26070 this.activeMinSize = this.getMinimumSize();;
26071 this.activeMaxSize = this.getMaximumSize();;
26072 var c1 = size - this.activeMinSize;
26073 var c2 = Math.max(this.activeMaxSize - size, 0);
26074 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26075 this.dd.resetConstraints();
26076 this.dd.setXConstraint(
26077 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26078 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26080 this.dd.setYConstraint(0, 0);
26082 this.dd.resetConstraints();
26083 this.dd.setXConstraint(0, 0);
26084 this.dd.setYConstraint(
26085 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26086 this.placement == Roo.SplitBar.TOP ? c2 : c1
26089 this.dragSpecs.startSize = size;
26090 this.dragSpecs.startPoint = [x, y];
26091 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26095 * @private Called after the drag operation by the DDProxy
26097 onEndProxyDrag : function(e){
26098 Roo.get(this.proxy).setDisplayed(false);
26099 var endPoint = Roo.lib.Event.getXY(e);
26101 this.overlay.hide();
26104 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26105 newSize = this.dragSpecs.startSize +
26106 (this.placement == Roo.SplitBar.LEFT ?
26107 endPoint[0] - this.dragSpecs.startPoint[0] :
26108 this.dragSpecs.startPoint[0] - endPoint[0]
26111 newSize = this.dragSpecs.startSize +
26112 (this.placement == Roo.SplitBar.TOP ?
26113 endPoint[1] - this.dragSpecs.startPoint[1] :
26114 this.dragSpecs.startPoint[1] - endPoint[1]
26117 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26118 if(newSize != this.dragSpecs.startSize){
26119 if(this.fireEvent('beforeapply', this, newSize) !== false){
26120 this.adapter.setElementSize(this, newSize);
26121 this.fireEvent("moved", this, newSize);
26122 this.fireEvent("resize", this, newSize);
26128 * Get the adapter this SplitBar uses
26129 * @return The adapter object
26131 getAdapter : function(){
26132 return this.adapter;
26136 * Set the adapter this SplitBar uses
26137 * @param {Object} adapter A SplitBar adapter object
26139 setAdapter : function(adapter){
26140 this.adapter = adapter;
26141 this.adapter.init(this);
26145 * Gets the minimum size for the resizing element
26146 * @return {Number} The minimum size
26148 getMinimumSize : function(){
26149 return this.minSize;
26153 * Sets the minimum size for the resizing element
26154 * @param {Number} minSize The minimum size
26156 setMinimumSize : function(minSize){
26157 this.minSize = minSize;
26161 * Gets the maximum size for the resizing element
26162 * @return {Number} The maximum size
26164 getMaximumSize : function(){
26165 return this.maxSize;
26169 * Sets the maximum size for the resizing element
26170 * @param {Number} maxSize The maximum size
26172 setMaximumSize : function(maxSize){
26173 this.maxSize = maxSize;
26177 * Sets the initialize size for the resizing element
26178 * @param {Number} size The initial size
26180 setCurrentSize : function(size){
26181 var oldAnimate = this.animate;
26182 this.animate = false;
26183 this.adapter.setElementSize(this, size);
26184 this.animate = oldAnimate;
26188 * Destroy this splitbar.
26189 * @param {Boolean} removeEl True to remove the element
26191 destroy : function(removeEl){
26193 this.shim.remove();
26196 this.proxy.parentNode.removeChild(this.proxy);
26204 * @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.
26206 Roo.SplitBar.createProxy = function(dir){
26207 var proxy = new Roo.Element(document.createElement("div"));
26208 proxy.unselectable();
26209 var cls = 'x-splitbar-proxy';
26210 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26211 document.body.appendChild(proxy.dom);
26216 * @class Roo.SplitBar.BasicLayoutAdapter
26217 * Default Adapter. It assumes the splitter and resizing element are not positioned
26218 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26220 Roo.SplitBar.BasicLayoutAdapter = function(){
26223 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26224 // do nothing for now
26225 init : function(s){
26229 * Called before drag operations to get the current size of the resizing element.
26230 * @param {Roo.SplitBar} s The SplitBar using this adapter
26232 getElementSize : function(s){
26233 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26234 return s.resizingEl.getWidth();
26236 return s.resizingEl.getHeight();
26241 * Called after drag operations to set the size of the resizing element.
26242 * @param {Roo.SplitBar} s The SplitBar using this adapter
26243 * @param {Number} newSize The new size to set
26244 * @param {Function} onComplete A function to be invoked when resizing is complete
26246 setElementSize : function(s, newSize, onComplete){
26247 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26249 s.resizingEl.setWidth(newSize);
26251 onComplete(s, newSize);
26254 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26259 s.resizingEl.setHeight(newSize);
26261 onComplete(s, newSize);
26264 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26271 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26272 * @extends Roo.SplitBar.BasicLayoutAdapter
26273 * Adapter that moves the splitter element to align with the resized sizing element.
26274 * Used with an absolute positioned SplitBar.
26275 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26276 * document.body, make sure you assign an id to the body element.
26278 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26279 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26280 this.container = Roo.get(container);
26283 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26284 init : function(s){
26285 this.basic.init(s);
26288 getElementSize : function(s){
26289 return this.basic.getElementSize(s);
26292 setElementSize : function(s, newSize, onComplete){
26293 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26296 moveSplitter : function(s){
26297 var yes = Roo.SplitBar;
26298 switch(s.placement){
26300 s.el.setX(s.resizingEl.getRight());
26303 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26306 s.el.setY(s.resizingEl.getBottom());
26309 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26316 * Orientation constant - Create a vertical SplitBar
26320 Roo.SplitBar.VERTICAL = 1;
26323 * Orientation constant - Create a horizontal SplitBar
26327 Roo.SplitBar.HORIZONTAL = 2;
26330 * Placement constant - The resizing element is to the left of the splitter element
26334 Roo.SplitBar.LEFT = 1;
26337 * Placement constant - The resizing element is to the right of the splitter element
26341 Roo.SplitBar.RIGHT = 2;
26344 * Placement constant - The resizing element is positioned above the splitter element
26348 Roo.SplitBar.TOP = 3;
26351 * Placement constant - The resizing element is positioned under splitter element
26355 Roo.SplitBar.BOTTOM = 4;
26358 * Ext JS Library 1.1.1
26359 * Copyright(c) 2006-2007, Ext JS, LLC.
26361 * Originally Released Under LGPL - original licence link has changed is not relivant.
26364 * <script type="text/javascript">
26369 * @extends Roo.util.Observable
26370 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26371 * This class also supports single and multi selection modes. <br>
26372 * Create a data model bound view:
26374 var store = new Roo.data.Store(...);
26376 var view = new Roo.View({
26378 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26380 singleSelect: true,
26381 selectedClass: "ydataview-selected",
26385 // listen for node click?
26386 view.on("click", function(vw, index, node, e){
26387 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26391 dataModel.load("foobar.xml");
26393 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26395 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26396 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26398 * Note: old style constructor is still suported (container, template, config)
26401 * Create a new View
26402 * @param {Object} config The config object
26405 Roo.View = function(config, depreciated_tpl, depreciated_config){
26407 this.parent = false;
26409 if (typeof(depreciated_tpl) == 'undefined') {
26410 // new way.. - universal constructor.
26411 Roo.apply(this, config);
26412 this.el = Roo.get(this.el);
26415 this.el = Roo.get(config);
26416 this.tpl = depreciated_tpl;
26417 Roo.apply(this, depreciated_config);
26419 this.wrapEl = this.el.wrap().wrap();
26420 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26423 if(typeof(this.tpl) == "string"){
26424 this.tpl = new Roo.Template(this.tpl);
26426 // support xtype ctors..
26427 this.tpl = new Roo.factory(this.tpl, Roo);
26431 this.tpl.compile();
26436 * @event beforeclick
26437 * Fires before a click is processed. Returns false to cancel the default action.
26438 * @param {Roo.View} this
26439 * @param {Number} index The index of the target node
26440 * @param {HTMLElement} node The target node
26441 * @param {Roo.EventObject} e The raw event object
26443 "beforeclick" : true,
26446 * Fires when a template node is clicked.
26447 * @param {Roo.View} this
26448 * @param {Number} index The index of the target node
26449 * @param {HTMLElement} node The target node
26450 * @param {Roo.EventObject} e The raw event object
26455 * Fires when a template node is double clicked.
26456 * @param {Roo.View} this
26457 * @param {Number} index The index of the target node
26458 * @param {HTMLElement} node The target node
26459 * @param {Roo.EventObject} e The raw event object
26463 * @event contextmenu
26464 * Fires when a template node is right clicked.
26465 * @param {Roo.View} this
26466 * @param {Number} index The index of the target node
26467 * @param {HTMLElement} node The target node
26468 * @param {Roo.EventObject} e The raw event object
26470 "contextmenu" : true,
26472 * @event selectionchange
26473 * Fires when the selected nodes change.
26474 * @param {Roo.View} this
26475 * @param {Array} selections Array of the selected nodes
26477 "selectionchange" : true,
26480 * @event beforeselect
26481 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26482 * @param {Roo.View} this
26483 * @param {HTMLElement} node The node to be selected
26484 * @param {Array} selections Array of currently selected nodes
26486 "beforeselect" : true,
26488 * @event preparedata
26489 * Fires on every row to render, to allow you to change the data.
26490 * @param {Roo.View} this
26491 * @param {Object} data to be rendered (change this)
26493 "preparedata" : true
26501 "click": this.onClick,
26502 "dblclick": this.onDblClick,
26503 "contextmenu": this.onContextMenu,
26507 this.selections = [];
26509 this.cmp = new Roo.CompositeElementLite([]);
26511 this.store = Roo.factory(this.store, Roo.data);
26512 this.setStore(this.store, true);
26515 if ( this.footer && this.footer.xtype) {
26517 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26519 this.footer.dataSource = this.store;
26520 this.footer.container = fctr;
26521 this.footer = Roo.factory(this.footer, Roo);
26522 fctr.insertFirst(this.el);
26524 // this is a bit insane - as the paging toolbar seems to detach the el..
26525 // dom.parentNode.parentNode.parentNode
26526 // they get detached?
26530 Roo.View.superclass.constructor.call(this);
26535 Roo.extend(Roo.View, Roo.util.Observable, {
26538 * @cfg {Roo.data.Store} store Data store to load data from.
26543 * @cfg {String|Roo.Element} el The container element.
26548 * @cfg {String|Roo.Template} tpl The template used by this View
26552 * @cfg {String} dataName the named area of the template to use as the data area
26553 * Works with domtemplates roo-name="name"
26557 * @cfg {String} selectedClass The css class to add to selected nodes
26559 selectedClass : "x-view-selected",
26561 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26566 * @cfg {String} text to display on mask (default Loading)
26570 * @cfg {Boolean} multiSelect Allow multiple selection
26572 multiSelect : false,
26574 * @cfg {Boolean} singleSelect Allow single selection
26576 singleSelect: false,
26579 * @cfg {Boolean} toggleSelect - selecting
26581 toggleSelect : false,
26584 * @cfg {Boolean} tickable - selecting
26589 * Returns the element this view is bound to.
26590 * @return {Roo.Element}
26592 getEl : function(){
26593 return this.wrapEl;
26599 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26601 refresh : function(){
26602 //Roo.log('refresh');
26605 // if we are using something like 'domtemplate', then
26606 // the what gets used is:
26607 // t.applySubtemplate(NAME, data, wrapping data..)
26608 // the outer template then get' applied with
26609 // the store 'extra data'
26610 // and the body get's added to the
26611 // roo-name="data" node?
26612 // <span class='roo-tpl-{name}'></span> ?????
26616 this.clearSelections();
26617 this.el.update("");
26619 var records = this.store.getRange();
26620 if(records.length < 1) {
26622 // is this valid?? = should it render a template??
26624 this.el.update(this.emptyText);
26628 if (this.dataName) {
26629 this.el.update(t.apply(this.store.meta)); //????
26630 el = this.el.child('.roo-tpl-' + this.dataName);
26633 for(var i = 0, len = records.length; i < len; i++){
26634 var data = this.prepareData(records[i].data, i, records[i]);
26635 this.fireEvent("preparedata", this, data, i, records[i]);
26637 var d = Roo.apply({}, data);
26640 Roo.apply(d, {'roo-id' : Roo.id()});
26644 Roo.each(this.parent.item, function(item){
26645 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26648 Roo.apply(d, {'roo-data-checked' : 'checked'});
26652 html[html.length] = Roo.util.Format.trim(
26654 t.applySubtemplate(this.dataName, d, this.store.meta) :
26661 el.update(html.join(""));
26662 this.nodes = el.dom.childNodes;
26663 this.updateIndexes(0);
26668 * Function to override to reformat the data that is sent to
26669 * the template for each node.
26670 * DEPRICATED - use the preparedata event handler.
26671 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26672 * a JSON object for an UpdateManager bound view).
26674 prepareData : function(data, index, record)
26676 this.fireEvent("preparedata", this, data, index, record);
26680 onUpdate : function(ds, record){
26681 // Roo.log('on update');
26682 this.clearSelections();
26683 var index = this.store.indexOf(record);
26684 var n = this.nodes[index];
26685 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26686 n.parentNode.removeChild(n);
26687 this.updateIndexes(index, index);
26693 onAdd : function(ds, records, index)
26695 //Roo.log(['on Add', ds, records, index] );
26696 this.clearSelections();
26697 if(this.nodes.length == 0){
26701 var n = this.nodes[index];
26702 for(var i = 0, len = records.length; i < len; i++){
26703 var d = this.prepareData(records[i].data, i, records[i]);
26705 this.tpl.insertBefore(n, d);
26708 this.tpl.append(this.el, d);
26711 this.updateIndexes(index);
26714 onRemove : function(ds, record, index){
26715 // Roo.log('onRemove');
26716 this.clearSelections();
26717 var el = this.dataName ?
26718 this.el.child('.roo-tpl-' + this.dataName) :
26721 el.dom.removeChild(this.nodes[index]);
26722 this.updateIndexes(index);
26726 * Refresh an individual node.
26727 * @param {Number} index
26729 refreshNode : function(index){
26730 this.onUpdate(this.store, this.store.getAt(index));
26733 updateIndexes : function(startIndex, endIndex){
26734 var ns = this.nodes;
26735 startIndex = startIndex || 0;
26736 endIndex = endIndex || ns.length - 1;
26737 for(var i = startIndex; i <= endIndex; i++){
26738 ns[i].nodeIndex = i;
26743 * Changes the data store this view uses and refresh the view.
26744 * @param {Store} store
26746 setStore : function(store, initial){
26747 if(!initial && this.store){
26748 this.store.un("datachanged", this.refresh);
26749 this.store.un("add", this.onAdd);
26750 this.store.un("remove", this.onRemove);
26751 this.store.un("update", this.onUpdate);
26752 this.store.un("clear", this.refresh);
26753 this.store.un("beforeload", this.onBeforeLoad);
26754 this.store.un("load", this.onLoad);
26755 this.store.un("loadexception", this.onLoad);
26759 store.on("datachanged", this.refresh, this);
26760 store.on("add", this.onAdd, this);
26761 store.on("remove", this.onRemove, this);
26762 store.on("update", this.onUpdate, this);
26763 store.on("clear", this.refresh, this);
26764 store.on("beforeload", this.onBeforeLoad, this);
26765 store.on("load", this.onLoad, this);
26766 store.on("loadexception", this.onLoad, this);
26774 * onbeforeLoad - masks the loading area.
26777 onBeforeLoad : function(store,opts)
26779 //Roo.log('onBeforeLoad');
26781 this.el.update("");
26783 this.el.mask(this.mask ? this.mask : "Loading" );
26785 onLoad : function ()
26792 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26793 * @param {HTMLElement} node
26794 * @return {HTMLElement} The template node
26796 findItemFromChild : function(node){
26797 var el = this.dataName ?
26798 this.el.child('.roo-tpl-' + this.dataName,true) :
26801 if(!node || node.parentNode == el){
26804 var p = node.parentNode;
26805 while(p && p != el){
26806 if(p.parentNode == el){
26815 onClick : function(e){
26816 var item = this.findItemFromChild(e.getTarget());
26818 var index = this.indexOf(item);
26819 if(this.onItemClick(item, index, e) !== false){
26820 this.fireEvent("click", this, index, item, e);
26823 this.clearSelections();
26828 onContextMenu : function(e){
26829 var item = this.findItemFromChild(e.getTarget());
26831 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26836 onDblClick : function(e){
26837 var item = this.findItemFromChild(e.getTarget());
26839 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26843 onItemClick : function(item, index, e)
26845 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26848 if (this.toggleSelect) {
26849 var m = this.isSelected(item) ? 'unselect' : 'select';
26852 _t[m](item, true, false);
26855 if(this.multiSelect || this.singleSelect){
26856 if(this.multiSelect && e.shiftKey && this.lastSelection){
26857 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26859 this.select(item, this.multiSelect && e.ctrlKey);
26860 this.lastSelection = item;
26863 if(!this.tickable){
26864 e.preventDefault();
26872 * Get the number of selected nodes.
26875 getSelectionCount : function(){
26876 return this.selections.length;
26880 * Get the currently selected nodes.
26881 * @return {Array} An array of HTMLElements
26883 getSelectedNodes : function(){
26884 return this.selections;
26888 * Get the indexes of the selected nodes.
26891 getSelectedIndexes : function(){
26892 var indexes = [], s = this.selections;
26893 for(var i = 0, len = s.length; i < len; i++){
26894 indexes.push(s[i].nodeIndex);
26900 * Clear all selections
26901 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26903 clearSelections : function(suppressEvent){
26904 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26905 this.cmp.elements = this.selections;
26906 this.cmp.removeClass(this.selectedClass);
26907 this.selections = [];
26908 if(!suppressEvent){
26909 this.fireEvent("selectionchange", this, this.selections);
26915 * Returns true if the passed node is selected
26916 * @param {HTMLElement/Number} node The node or node index
26917 * @return {Boolean}
26919 isSelected : function(node){
26920 var s = this.selections;
26924 node = this.getNode(node);
26925 return s.indexOf(node) !== -1;
26930 * @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
26931 * @param {Boolean} keepExisting (optional) true to keep existing selections
26932 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26934 select : function(nodeInfo, keepExisting, suppressEvent){
26935 if(nodeInfo instanceof Array){
26937 this.clearSelections(true);
26939 for(var i = 0, len = nodeInfo.length; i < len; i++){
26940 this.select(nodeInfo[i], true, true);
26944 var node = this.getNode(nodeInfo);
26945 if(!node || this.isSelected(node)){
26946 return; // already selected.
26949 this.clearSelections(true);
26952 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26953 Roo.fly(node).addClass(this.selectedClass);
26954 this.selections.push(node);
26955 if(!suppressEvent){
26956 this.fireEvent("selectionchange", this, this.selections);
26964 * @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
26965 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26966 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26968 unselect : function(nodeInfo, keepExisting, suppressEvent)
26970 if(nodeInfo instanceof Array){
26971 Roo.each(this.selections, function(s) {
26972 this.unselect(s, nodeInfo);
26976 var node = this.getNode(nodeInfo);
26977 if(!node || !this.isSelected(node)){
26978 //Roo.log("not selected");
26979 return; // not selected.
26983 Roo.each(this.selections, function(s) {
26985 Roo.fly(node).removeClass(this.selectedClass);
26992 this.selections= ns;
26993 this.fireEvent("selectionchange", this, this.selections);
26997 * Gets a template node.
26998 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26999 * @return {HTMLElement} The node or null if it wasn't found
27001 getNode : function(nodeInfo){
27002 if(typeof nodeInfo == "string"){
27003 return document.getElementById(nodeInfo);
27004 }else if(typeof nodeInfo == "number"){
27005 return this.nodes[nodeInfo];
27011 * Gets a range template nodes.
27012 * @param {Number} startIndex
27013 * @param {Number} endIndex
27014 * @return {Array} An array of nodes
27016 getNodes : function(start, end){
27017 var ns = this.nodes;
27018 start = start || 0;
27019 end = typeof end == "undefined" ? ns.length - 1 : end;
27022 for(var i = start; i <= end; i++){
27026 for(var i = start; i >= end; i--){
27034 * Finds the index of the passed node
27035 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27036 * @return {Number} The index of the node or -1
27038 indexOf : function(node){
27039 node = this.getNode(node);
27040 if(typeof node.nodeIndex == "number"){
27041 return node.nodeIndex;
27043 var ns = this.nodes;
27044 for(var i = 0, len = ns.length; i < len; i++){
27054 * Ext JS Library 1.1.1
27055 * Copyright(c) 2006-2007, Ext JS, LLC.
27057 * Originally Released Under LGPL - original licence link has changed is not relivant.
27060 * <script type="text/javascript">
27064 * @class Roo.JsonView
27065 * @extends Roo.View
27066 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27068 var view = new Roo.JsonView({
27069 container: "my-element",
27070 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27075 // listen for node click?
27076 view.on("click", function(vw, index, node, e){
27077 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27080 // direct load of JSON data
27081 view.load("foobar.php");
27083 // Example from my blog list
27084 var tpl = new Roo.Template(
27085 '<div class="entry">' +
27086 '<a class="entry-title" href="{link}">{title}</a>' +
27087 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27088 "</div><hr />"
27091 var moreView = new Roo.JsonView({
27092 container : "entry-list",
27096 moreView.on("beforerender", this.sortEntries, this);
27098 url: "/blog/get-posts.php",
27099 params: "allposts=true",
27100 text: "Loading Blog Entries..."
27104 * Note: old code is supported with arguments : (container, template, config)
27108 * Create a new JsonView
27110 * @param {Object} config The config object
27113 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27116 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27118 var um = this.el.getUpdateManager();
27119 um.setRenderer(this);
27120 um.on("update", this.onLoad, this);
27121 um.on("failure", this.onLoadException, this);
27124 * @event beforerender
27125 * Fires before rendering of the downloaded JSON data.
27126 * @param {Roo.JsonView} this
27127 * @param {Object} data The JSON data loaded
27131 * Fires when data is loaded.
27132 * @param {Roo.JsonView} this
27133 * @param {Object} data The JSON data loaded
27134 * @param {Object} response The raw Connect response object
27137 * @event loadexception
27138 * Fires when loading fails.
27139 * @param {Roo.JsonView} this
27140 * @param {Object} response The raw Connect response object
27143 'beforerender' : true,
27145 'loadexception' : true
27148 Roo.extend(Roo.JsonView, Roo.View, {
27150 * @type {String} The root property in the loaded JSON object that contains the data
27155 * Refreshes the view.
27157 refresh : function(){
27158 this.clearSelections();
27159 this.el.update("");
27161 var o = this.jsonData;
27162 if(o && o.length > 0){
27163 for(var i = 0, len = o.length; i < len; i++){
27164 var data = this.prepareData(o[i], i, o);
27165 html[html.length] = this.tpl.apply(data);
27168 html.push(this.emptyText);
27170 this.el.update(html.join(""));
27171 this.nodes = this.el.dom.childNodes;
27172 this.updateIndexes(0);
27176 * 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.
27177 * @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:
27180 url: "your-url.php",
27181 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27182 callback: yourFunction,
27183 scope: yourObject, //(optional scope)
27186 text: "Loading...",
27191 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27192 * 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.
27193 * @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}
27194 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27195 * @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.
27198 var um = this.el.getUpdateManager();
27199 um.update.apply(um, arguments);
27202 // note - render is a standard framework call...
27203 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27204 render : function(el, response){
27206 this.clearSelections();
27207 this.el.update("");
27210 if (response != '') {
27211 o = Roo.util.JSON.decode(response.responseText);
27214 o = o[this.jsonRoot];
27220 * The current JSON data or null
27223 this.beforeRender();
27228 * Get the number of records in the current JSON dataset
27231 getCount : function(){
27232 return this.jsonData ? this.jsonData.length : 0;
27236 * Returns the JSON object for the specified node(s)
27237 * @param {HTMLElement/Array} node The node or an array of nodes
27238 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27239 * you get the JSON object for the node
27241 getNodeData : function(node){
27242 if(node instanceof Array){
27244 for(var i = 0, len = node.length; i < len; i++){
27245 data.push(this.getNodeData(node[i]));
27249 return this.jsonData[this.indexOf(node)] || null;
27252 beforeRender : function(){
27253 this.snapshot = this.jsonData;
27255 this.sort.apply(this, this.sortInfo);
27257 this.fireEvent("beforerender", this, this.jsonData);
27260 onLoad : function(el, o){
27261 this.fireEvent("load", this, this.jsonData, o);
27264 onLoadException : function(el, o){
27265 this.fireEvent("loadexception", this, o);
27269 * Filter the data by a specific property.
27270 * @param {String} property A property on your JSON objects
27271 * @param {String/RegExp} value Either string that the property values
27272 * should start with, or a RegExp to test against the property
27274 filter : function(property, value){
27277 var ss = this.snapshot;
27278 if(typeof value == "string"){
27279 var vlen = value.length;
27281 this.clearFilter();
27284 value = value.toLowerCase();
27285 for(var i = 0, len = ss.length; i < len; i++){
27287 if(o[property].substr(0, vlen).toLowerCase() == value){
27291 } else if(value.exec){ // regex?
27292 for(var i = 0, len = ss.length; i < len; i++){
27294 if(value.test(o[property])){
27301 this.jsonData = data;
27307 * Filter by a function. The passed function will be called with each
27308 * object in the current dataset. If the function returns true the value is kept,
27309 * otherwise it is filtered.
27310 * @param {Function} fn
27311 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27313 filterBy : function(fn, scope){
27316 var ss = this.snapshot;
27317 for(var i = 0, len = ss.length; i < len; i++){
27319 if(fn.call(scope || this, o)){
27323 this.jsonData = data;
27329 * Clears the current filter.
27331 clearFilter : function(){
27332 if(this.snapshot && this.jsonData != this.snapshot){
27333 this.jsonData = this.snapshot;
27340 * Sorts the data for this view and refreshes it.
27341 * @param {String} property A property on your JSON objects to sort on
27342 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27343 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27345 sort : function(property, dir, sortType){
27346 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27349 var dsc = dir && dir.toLowerCase() == "desc";
27350 var f = function(o1, o2){
27351 var v1 = sortType ? sortType(o1[p]) : o1[p];
27352 var v2 = sortType ? sortType(o2[p]) : o2[p];
27355 return dsc ? +1 : -1;
27356 } else if(v1 > v2){
27357 return dsc ? -1 : +1;
27362 this.jsonData.sort(f);
27364 if(this.jsonData != this.snapshot){
27365 this.snapshot.sort(f);
27371 * Ext JS Library 1.1.1
27372 * Copyright(c) 2006-2007, Ext JS, LLC.
27374 * Originally Released Under LGPL - original licence link has changed is not relivant.
27377 * <script type="text/javascript">
27382 * @class Roo.ColorPalette
27383 * @extends Roo.Component
27384 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27385 * Here's an example of typical usage:
27387 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27388 cp.render('my-div');
27390 cp.on('select', function(palette, selColor){
27391 // do something with selColor
27395 * Create a new ColorPalette
27396 * @param {Object} config The config object
27398 Roo.ColorPalette = function(config){
27399 Roo.ColorPalette.superclass.constructor.call(this, config);
27403 * Fires when a color is selected
27404 * @param {ColorPalette} this
27405 * @param {String} color The 6-digit color hex code (without the # symbol)
27411 this.on("select", this.handler, this.scope, true);
27414 Roo.extend(Roo.ColorPalette, Roo.Component, {
27416 * @cfg {String} itemCls
27417 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27419 itemCls : "x-color-palette",
27421 * @cfg {String} value
27422 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27423 * the hex codes are case-sensitive.
27426 clickEvent:'click',
27428 ctype: "Roo.ColorPalette",
27431 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27433 allowReselect : false,
27436 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27437 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27438 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27439 * of colors with the width setting until the box is symmetrical.</p>
27440 * <p>You can override individual colors if needed:</p>
27442 var cp = new Roo.ColorPalette();
27443 cp.colors[0] = "FF0000"; // change the first box to red
27446 Or you can provide a custom array of your own for complete control:
27448 var cp = new Roo.ColorPalette();
27449 cp.colors = ["000000", "993300", "333300"];
27454 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27455 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27456 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27457 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27458 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27462 onRender : function(container, position){
27463 var t = new Roo.MasterTemplate(
27464 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27466 var c = this.colors;
27467 for(var i = 0, len = c.length; i < len; i++){
27470 var el = document.createElement("div");
27471 el.className = this.itemCls;
27473 container.dom.insertBefore(el, position);
27474 this.el = Roo.get(el);
27475 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27476 if(this.clickEvent != 'click'){
27477 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27482 afterRender : function(){
27483 Roo.ColorPalette.superclass.afterRender.call(this);
27485 var s = this.value;
27492 handleClick : function(e, t){
27493 e.preventDefault();
27494 if(!this.disabled){
27495 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27496 this.select(c.toUpperCase());
27501 * Selects the specified color in the palette (fires the select event)
27502 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27504 select : function(color){
27505 color = color.replace("#", "");
27506 if(color != this.value || this.allowReselect){
27509 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27511 el.child("a.color-"+color).addClass("x-color-palette-sel");
27512 this.value = color;
27513 this.fireEvent("select", this, color);
27518 * Ext JS Library 1.1.1
27519 * Copyright(c) 2006-2007, Ext JS, LLC.
27521 * Originally Released Under LGPL - original licence link has changed is not relivant.
27524 * <script type="text/javascript">
27528 * @class Roo.DatePicker
27529 * @extends Roo.Component
27530 * Simple date picker class.
27532 * Create a new DatePicker
27533 * @param {Object} config The config object
27535 Roo.DatePicker = function(config){
27536 Roo.DatePicker.superclass.constructor.call(this, config);
27538 this.value = config && config.value ?
27539 config.value.clearTime() : new Date().clearTime();
27544 * Fires when a date is selected
27545 * @param {DatePicker} this
27546 * @param {Date} date The selected date
27550 * @event monthchange
27551 * Fires when the displayed month changes
27552 * @param {DatePicker} this
27553 * @param {Date} date The selected month
27555 'monthchange': true
27559 this.on("select", this.handler, this.scope || this);
27561 // build the disabledDatesRE
27562 if(!this.disabledDatesRE && this.disabledDates){
27563 var dd = this.disabledDates;
27565 for(var i = 0; i < dd.length; i++){
27567 if(i != dd.length-1) {
27571 this.disabledDatesRE = new RegExp(re + ")");
27575 Roo.extend(Roo.DatePicker, Roo.Component, {
27577 * @cfg {String} todayText
27578 * The text to display on the button that selects the current date (defaults to "Today")
27580 todayText : "Today",
27582 * @cfg {String} okText
27583 * The text to display on the ok button
27585 okText : " OK ", //   to give the user extra clicking room
27587 * @cfg {String} cancelText
27588 * The text to display on the cancel button
27590 cancelText : "Cancel",
27592 * @cfg {String} todayTip
27593 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27595 todayTip : "{0} (Spacebar)",
27597 * @cfg {Date} minDate
27598 * Minimum allowable date (JavaScript date object, defaults to null)
27602 * @cfg {Date} maxDate
27603 * Maximum allowable date (JavaScript date object, defaults to null)
27607 * @cfg {String} minText
27608 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27610 minText : "This date is before the minimum date",
27612 * @cfg {String} maxText
27613 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27615 maxText : "This date is after the maximum date",
27617 * @cfg {String} format
27618 * The default date format string which can be overriden for localization support. The format must be
27619 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27623 * @cfg {Array} disabledDays
27624 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27626 disabledDays : null,
27628 * @cfg {String} disabledDaysText
27629 * The tooltip to display when the date falls on a disabled day (defaults to "")
27631 disabledDaysText : "",
27633 * @cfg {RegExp} disabledDatesRE
27634 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27636 disabledDatesRE : null,
27638 * @cfg {String} disabledDatesText
27639 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27641 disabledDatesText : "",
27643 * @cfg {Boolean} constrainToViewport
27644 * True to constrain the date picker to the viewport (defaults to true)
27646 constrainToViewport : true,
27648 * @cfg {Array} monthNames
27649 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27651 monthNames : Date.monthNames,
27653 * @cfg {Array} dayNames
27654 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27656 dayNames : Date.dayNames,
27658 * @cfg {String} nextText
27659 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27661 nextText: 'Next Month (Control+Right)',
27663 * @cfg {String} prevText
27664 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27666 prevText: 'Previous Month (Control+Left)',
27668 * @cfg {String} monthYearText
27669 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27671 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27673 * @cfg {Number} startDay
27674 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27678 * @cfg {Bool} showClear
27679 * Show a clear button (usefull for date form elements that can be blank.)
27685 * Sets the value of the date field
27686 * @param {Date} value The date to set
27688 setValue : function(value){
27689 var old = this.value;
27691 if (typeof(value) == 'string') {
27693 value = Date.parseDate(value, this.format);
27696 value = new Date();
27699 this.value = value.clearTime(true);
27701 this.update(this.value);
27706 * Gets the current selected value of the date field
27707 * @return {Date} The selected date
27709 getValue : function(){
27714 focus : function(){
27716 this.update(this.activeDate);
27721 onRender : function(container, position){
27724 '<table cellspacing="0">',
27725 '<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>',
27726 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27727 var dn = this.dayNames;
27728 for(var i = 0; i < 7; i++){
27729 var d = this.startDay+i;
27733 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27735 m[m.length] = "</tr></thead><tbody><tr>";
27736 for(var i = 0; i < 42; i++) {
27737 if(i % 7 == 0 && i != 0){
27738 m[m.length] = "</tr><tr>";
27740 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27742 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27743 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27745 var el = document.createElement("div");
27746 el.className = "x-date-picker";
27747 el.innerHTML = m.join("");
27749 container.dom.insertBefore(el, position);
27751 this.el = Roo.get(el);
27752 this.eventEl = Roo.get(el.firstChild);
27754 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27755 handler: this.showPrevMonth,
27757 preventDefault:true,
27761 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27762 handler: this.showNextMonth,
27764 preventDefault:true,
27768 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27770 this.monthPicker = this.el.down('div.x-date-mp');
27771 this.monthPicker.enableDisplayMode('block');
27773 var kn = new Roo.KeyNav(this.eventEl, {
27774 "left" : function(e){
27776 this.showPrevMonth() :
27777 this.update(this.activeDate.add("d", -1));
27780 "right" : function(e){
27782 this.showNextMonth() :
27783 this.update(this.activeDate.add("d", 1));
27786 "up" : function(e){
27788 this.showNextYear() :
27789 this.update(this.activeDate.add("d", -7));
27792 "down" : function(e){
27794 this.showPrevYear() :
27795 this.update(this.activeDate.add("d", 7));
27798 "pageUp" : function(e){
27799 this.showNextMonth();
27802 "pageDown" : function(e){
27803 this.showPrevMonth();
27806 "enter" : function(e){
27807 e.stopPropagation();
27814 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27816 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27818 this.el.unselectable();
27820 this.cells = this.el.select("table.x-date-inner tbody td");
27821 this.textNodes = this.el.query("table.x-date-inner tbody span");
27823 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27825 tooltip: this.monthYearText
27828 this.mbtn.on('click', this.showMonthPicker, this);
27829 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27832 var today = (new Date()).dateFormat(this.format);
27834 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27835 if (this.showClear) {
27836 baseTb.add( new Roo.Toolbar.Fill());
27839 text: String.format(this.todayText, today),
27840 tooltip: String.format(this.todayTip, today),
27841 handler: this.selectToday,
27845 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27848 if (this.showClear) {
27850 baseTb.add( new Roo.Toolbar.Fill());
27853 cls: 'x-btn-icon x-btn-clear',
27854 handler: function() {
27856 this.fireEvent("select", this, '');
27866 this.update(this.value);
27869 createMonthPicker : function(){
27870 if(!this.monthPicker.dom.firstChild){
27871 var buf = ['<table border="0" cellspacing="0">'];
27872 for(var i = 0; i < 6; i++){
27874 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27875 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27877 '<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>' :
27878 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27882 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27884 '</button><button type="button" class="x-date-mp-cancel">',
27886 '</button></td></tr>',
27889 this.monthPicker.update(buf.join(''));
27890 this.monthPicker.on('click', this.onMonthClick, this);
27891 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27893 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27894 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27896 this.mpMonths.each(function(m, a, i){
27899 m.dom.xmonth = 5 + Math.round(i * .5);
27901 m.dom.xmonth = Math.round((i-1) * .5);
27907 showMonthPicker : function(){
27908 this.createMonthPicker();
27909 var size = this.el.getSize();
27910 this.monthPicker.setSize(size);
27911 this.monthPicker.child('table').setSize(size);
27913 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27914 this.updateMPMonth(this.mpSelMonth);
27915 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27916 this.updateMPYear(this.mpSelYear);
27918 this.monthPicker.slideIn('t', {duration:.2});
27921 updateMPYear : function(y){
27923 var ys = this.mpYears.elements;
27924 for(var i = 1; i <= 10; i++){
27925 var td = ys[i-1], y2;
27927 y2 = y + Math.round(i * .5);
27928 td.firstChild.innerHTML = y2;
27931 y2 = y - (5-Math.round(i * .5));
27932 td.firstChild.innerHTML = y2;
27935 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27939 updateMPMonth : function(sm){
27940 this.mpMonths.each(function(m, a, i){
27941 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27945 selectMPMonth: function(m){
27949 onMonthClick : function(e, t){
27951 var el = new Roo.Element(t), pn;
27952 if(el.is('button.x-date-mp-cancel')){
27953 this.hideMonthPicker();
27955 else if(el.is('button.x-date-mp-ok')){
27956 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27957 this.hideMonthPicker();
27959 else if(pn = el.up('td.x-date-mp-month', 2)){
27960 this.mpMonths.removeClass('x-date-mp-sel');
27961 pn.addClass('x-date-mp-sel');
27962 this.mpSelMonth = pn.dom.xmonth;
27964 else if(pn = el.up('td.x-date-mp-year', 2)){
27965 this.mpYears.removeClass('x-date-mp-sel');
27966 pn.addClass('x-date-mp-sel');
27967 this.mpSelYear = pn.dom.xyear;
27969 else if(el.is('a.x-date-mp-prev')){
27970 this.updateMPYear(this.mpyear-10);
27972 else if(el.is('a.x-date-mp-next')){
27973 this.updateMPYear(this.mpyear+10);
27977 onMonthDblClick : function(e, t){
27979 var el = new Roo.Element(t), pn;
27980 if(pn = el.up('td.x-date-mp-month', 2)){
27981 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27982 this.hideMonthPicker();
27984 else if(pn = el.up('td.x-date-mp-year', 2)){
27985 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27986 this.hideMonthPicker();
27990 hideMonthPicker : function(disableAnim){
27991 if(this.monthPicker){
27992 if(disableAnim === true){
27993 this.monthPicker.hide();
27995 this.monthPicker.slideOut('t', {duration:.2});
28001 showPrevMonth : function(e){
28002 this.update(this.activeDate.add("mo", -1));
28006 showNextMonth : function(e){
28007 this.update(this.activeDate.add("mo", 1));
28011 showPrevYear : function(){
28012 this.update(this.activeDate.add("y", -1));
28016 showNextYear : function(){
28017 this.update(this.activeDate.add("y", 1));
28021 handleMouseWheel : function(e){
28022 var delta = e.getWheelDelta();
28024 this.showPrevMonth();
28026 } else if(delta < 0){
28027 this.showNextMonth();
28033 handleDateClick : function(e, t){
28035 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28036 this.setValue(new Date(t.dateValue));
28037 this.fireEvent("select", this, this.value);
28042 selectToday : function(){
28043 this.setValue(new Date().clearTime());
28044 this.fireEvent("select", this, this.value);
28048 update : function(date)
28050 var vd = this.activeDate;
28051 this.activeDate = date;
28053 var t = date.getTime();
28054 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28055 this.cells.removeClass("x-date-selected");
28056 this.cells.each(function(c){
28057 if(c.dom.firstChild.dateValue == t){
28058 c.addClass("x-date-selected");
28059 setTimeout(function(){
28060 try{c.dom.firstChild.focus();}catch(e){}
28069 var days = date.getDaysInMonth();
28070 var firstOfMonth = date.getFirstDateOfMonth();
28071 var startingPos = firstOfMonth.getDay()-this.startDay;
28073 if(startingPos <= this.startDay){
28077 var pm = date.add("mo", -1);
28078 var prevStart = pm.getDaysInMonth()-startingPos;
28080 var cells = this.cells.elements;
28081 var textEls = this.textNodes;
28082 days += startingPos;
28084 // convert everything to numbers so it's fast
28085 var day = 86400000;
28086 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28087 var today = new Date().clearTime().getTime();
28088 var sel = date.clearTime().getTime();
28089 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28090 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28091 var ddMatch = this.disabledDatesRE;
28092 var ddText = this.disabledDatesText;
28093 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28094 var ddaysText = this.disabledDaysText;
28095 var format = this.format;
28097 var setCellClass = function(cal, cell){
28099 var t = d.getTime();
28100 cell.firstChild.dateValue = t;
28102 cell.className += " x-date-today";
28103 cell.title = cal.todayText;
28106 cell.className += " x-date-selected";
28107 setTimeout(function(){
28108 try{cell.firstChild.focus();}catch(e){}
28113 cell.className = " x-date-disabled";
28114 cell.title = cal.minText;
28118 cell.className = " x-date-disabled";
28119 cell.title = cal.maxText;
28123 if(ddays.indexOf(d.getDay()) != -1){
28124 cell.title = ddaysText;
28125 cell.className = " x-date-disabled";
28128 if(ddMatch && format){
28129 var fvalue = d.dateFormat(format);
28130 if(ddMatch.test(fvalue)){
28131 cell.title = ddText.replace("%0", fvalue);
28132 cell.className = " x-date-disabled";
28138 for(; i < startingPos; i++) {
28139 textEls[i].innerHTML = (++prevStart);
28140 d.setDate(d.getDate()+1);
28141 cells[i].className = "x-date-prevday";
28142 setCellClass(this, cells[i]);
28144 for(; i < days; i++){
28145 intDay = i - startingPos + 1;
28146 textEls[i].innerHTML = (intDay);
28147 d.setDate(d.getDate()+1);
28148 cells[i].className = "x-date-active";
28149 setCellClass(this, cells[i]);
28152 for(; i < 42; i++) {
28153 textEls[i].innerHTML = (++extraDays);
28154 d.setDate(d.getDate()+1);
28155 cells[i].className = "x-date-nextday";
28156 setCellClass(this, cells[i]);
28159 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28160 this.fireEvent('monthchange', this, date);
28162 if(!this.internalRender){
28163 var main = this.el.dom.firstChild;
28164 var w = main.offsetWidth;
28165 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28166 Roo.fly(main).setWidth(w);
28167 this.internalRender = true;
28168 // opera does not respect the auto grow header center column
28169 // then, after it gets a width opera refuses to recalculate
28170 // without a second pass
28171 if(Roo.isOpera && !this.secondPass){
28172 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28173 this.secondPass = true;
28174 this.update.defer(10, this, [date]);
28182 * Ext JS Library 1.1.1
28183 * Copyright(c) 2006-2007, Ext JS, LLC.
28185 * Originally Released Under LGPL - original licence link has changed is not relivant.
28188 * <script type="text/javascript">
28191 * @class Roo.TabPanel
28192 * @extends Roo.util.Observable
28193 * A lightweight tab container.
28197 // basic tabs 1, built from existing content
28198 var tabs = new Roo.TabPanel("tabs1");
28199 tabs.addTab("script", "View Script");
28200 tabs.addTab("markup", "View Markup");
28201 tabs.activate("script");
28203 // more advanced tabs, built from javascript
28204 var jtabs = new Roo.TabPanel("jtabs");
28205 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28207 // set up the UpdateManager
28208 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28209 var updater = tab2.getUpdateManager();
28210 updater.setDefaultUrl("ajax1.htm");
28211 tab2.on('activate', updater.refresh, updater, true);
28213 // Use setUrl for Ajax loading
28214 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28215 tab3.setUrl("ajax2.htm", null, true);
28218 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28221 jtabs.activate("jtabs-1");
28224 * Create a new TabPanel.
28225 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28226 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28228 Roo.TabPanel = function(container, config){
28230 * The container element for this TabPanel.
28231 * @type Roo.Element
28233 this.el = Roo.get(container, true);
28235 if(typeof config == "boolean"){
28236 this.tabPosition = config ? "bottom" : "top";
28238 Roo.apply(this, config);
28241 if(this.tabPosition == "bottom"){
28242 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28243 this.el.addClass("x-tabs-bottom");
28245 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28246 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28247 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28249 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28251 if(this.tabPosition != "bottom"){
28252 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28253 * @type Roo.Element
28255 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28256 this.el.addClass("x-tabs-top");
28260 this.bodyEl.setStyle("position", "relative");
28262 this.active = null;
28263 this.activateDelegate = this.activate.createDelegate(this);
28268 * Fires when the active tab changes
28269 * @param {Roo.TabPanel} this
28270 * @param {Roo.TabPanelItem} activePanel The new active tab
28274 * @event beforetabchange
28275 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28276 * @param {Roo.TabPanel} this
28277 * @param {Object} e Set cancel to true on this object to cancel the tab change
28278 * @param {Roo.TabPanelItem} tab The tab being changed to
28280 "beforetabchange" : true
28283 Roo.EventManager.onWindowResize(this.onResize, this);
28284 this.cpad = this.el.getPadding("lr");
28285 this.hiddenCount = 0;
28288 // toolbar on the tabbar support...
28289 if (this.toolbar) {
28290 var tcfg = this.toolbar;
28291 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28292 this.toolbar = new Roo.Toolbar(tcfg);
28293 if (Roo.isSafari) {
28294 var tbl = tcfg.container.child('table', true);
28295 tbl.setAttribute('width', '100%');
28302 Roo.TabPanel.superclass.constructor.call(this);
28305 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28307 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28309 tabPosition : "top",
28311 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28313 currentTabWidth : 0,
28315 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28319 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28323 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28325 preferredTabWidth : 175,
28327 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28329 resizeTabs : false,
28331 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28333 monitorResize : true,
28335 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28340 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28341 * @param {String} id The id of the div to use <b>or create</b>
28342 * @param {String} text The text for the tab
28343 * @param {String} content (optional) Content to put in the TabPanelItem body
28344 * @param {Boolean} closable (optional) True to create a close icon on the tab
28345 * @return {Roo.TabPanelItem} The created TabPanelItem
28347 addTab : function(id, text, content, closable){
28348 var item = new Roo.TabPanelItem(this, id, text, closable);
28349 this.addTabItem(item);
28351 item.setContent(content);
28357 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28358 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28359 * @return {Roo.TabPanelItem}
28361 getTab : function(id){
28362 return this.items[id];
28366 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28367 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28369 hideTab : function(id){
28370 var t = this.items[id];
28373 this.hiddenCount++;
28374 this.autoSizeTabs();
28379 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28380 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28382 unhideTab : function(id){
28383 var t = this.items[id];
28385 t.setHidden(false);
28386 this.hiddenCount--;
28387 this.autoSizeTabs();
28392 * Adds an existing {@link Roo.TabPanelItem}.
28393 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28395 addTabItem : function(item){
28396 this.items[item.id] = item;
28397 this.items.push(item);
28398 if(this.resizeTabs){
28399 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28400 this.autoSizeTabs();
28407 * Removes a {@link Roo.TabPanelItem}.
28408 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28410 removeTab : function(id){
28411 var items = this.items;
28412 var tab = items[id];
28413 if(!tab) { return; }
28414 var index = items.indexOf(tab);
28415 if(this.active == tab && items.length > 1){
28416 var newTab = this.getNextAvailable(index);
28421 this.stripEl.dom.removeChild(tab.pnode.dom);
28422 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28423 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28425 items.splice(index, 1);
28426 delete this.items[tab.id];
28427 tab.fireEvent("close", tab);
28428 tab.purgeListeners();
28429 this.autoSizeTabs();
28432 getNextAvailable : function(start){
28433 var items = this.items;
28435 // look for a next tab that will slide over to
28436 // replace the one being removed
28437 while(index < items.length){
28438 var item = items[++index];
28439 if(item && !item.isHidden()){
28443 // if one isn't found select the previous tab (on the left)
28446 var item = items[--index];
28447 if(item && !item.isHidden()){
28455 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28456 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28458 disableTab : function(id){
28459 var tab = this.items[id];
28460 if(tab && this.active != tab){
28466 * Enables a {@link Roo.TabPanelItem} that is disabled.
28467 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28469 enableTab : function(id){
28470 var tab = this.items[id];
28475 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28476 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28477 * @return {Roo.TabPanelItem} The TabPanelItem.
28479 activate : function(id){
28480 var tab = this.items[id];
28484 if(tab == this.active || tab.disabled){
28488 this.fireEvent("beforetabchange", this, e, tab);
28489 if(e.cancel !== true && !tab.disabled){
28491 this.active.hide();
28493 this.active = this.items[id];
28494 this.active.show();
28495 this.fireEvent("tabchange", this, this.active);
28501 * Gets the active {@link Roo.TabPanelItem}.
28502 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28504 getActiveTab : function(){
28505 return this.active;
28509 * Updates the tab body element to fit the height of the container element
28510 * for overflow scrolling
28511 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28513 syncHeight : function(targetHeight){
28514 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28515 var bm = this.bodyEl.getMargins();
28516 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28517 this.bodyEl.setHeight(newHeight);
28521 onResize : function(){
28522 if(this.monitorResize){
28523 this.autoSizeTabs();
28528 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28530 beginUpdate : function(){
28531 this.updating = true;
28535 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28537 endUpdate : function(){
28538 this.updating = false;
28539 this.autoSizeTabs();
28543 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28545 autoSizeTabs : function(){
28546 var count = this.items.length;
28547 var vcount = count - this.hiddenCount;
28548 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28551 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28552 var availWidth = Math.floor(w / vcount);
28553 var b = this.stripBody;
28554 if(b.getWidth() > w){
28555 var tabs = this.items;
28556 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28557 if(availWidth < this.minTabWidth){
28558 /*if(!this.sleft){ // incomplete scrolling code
28559 this.createScrollButtons();
28562 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28565 if(this.currentTabWidth < this.preferredTabWidth){
28566 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28572 * Returns the number of tabs in this TabPanel.
28575 getCount : function(){
28576 return this.items.length;
28580 * Resizes all the tabs to the passed width
28581 * @param {Number} The new width
28583 setTabWidth : function(width){
28584 this.currentTabWidth = width;
28585 for(var i = 0, len = this.items.length; i < len; i++) {
28586 if(!this.items[i].isHidden()) {
28587 this.items[i].setWidth(width);
28593 * Destroys this TabPanel
28594 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28596 destroy : function(removeEl){
28597 Roo.EventManager.removeResizeListener(this.onResize, this);
28598 for(var i = 0, len = this.items.length; i < len; i++){
28599 this.items[i].purgeListeners();
28601 if(removeEl === true){
28602 this.el.update("");
28609 * @class Roo.TabPanelItem
28610 * @extends Roo.util.Observable
28611 * Represents an individual item (tab plus body) in a TabPanel.
28612 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28613 * @param {String} id The id of this TabPanelItem
28614 * @param {String} text The text for the tab of this TabPanelItem
28615 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28617 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28619 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28620 * @type Roo.TabPanel
28622 this.tabPanel = tabPanel;
28624 * The id for this TabPanelItem
28629 this.disabled = false;
28633 this.loaded = false;
28634 this.closable = closable;
28637 * The body element for this TabPanelItem.
28638 * @type Roo.Element
28640 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28641 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28642 this.bodyEl.setStyle("display", "block");
28643 this.bodyEl.setStyle("zoom", "1");
28646 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28648 this.el = Roo.get(els.el, true);
28649 this.inner = Roo.get(els.inner, true);
28650 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28651 this.pnode = Roo.get(els.el.parentNode, true);
28652 this.el.on("mousedown", this.onTabMouseDown, this);
28653 this.el.on("click", this.onTabClick, this);
28656 var c = Roo.get(els.close, true);
28657 c.dom.title = this.closeText;
28658 c.addClassOnOver("close-over");
28659 c.on("click", this.closeClick, this);
28665 * Fires when this tab becomes the active tab.
28666 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28667 * @param {Roo.TabPanelItem} this
28671 * @event beforeclose
28672 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28673 * @param {Roo.TabPanelItem} this
28674 * @param {Object} e Set cancel to true on this object to cancel the close.
28676 "beforeclose": true,
28679 * Fires when this tab is closed.
28680 * @param {Roo.TabPanelItem} this
28684 * @event deactivate
28685 * Fires when this tab is no longer the active tab.
28686 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28687 * @param {Roo.TabPanelItem} this
28689 "deactivate" : true
28691 this.hidden = false;
28693 Roo.TabPanelItem.superclass.constructor.call(this);
28696 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28697 purgeListeners : function(){
28698 Roo.util.Observable.prototype.purgeListeners.call(this);
28699 this.el.removeAllListeners();
28702 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28705 this.pnode.addClass("on");
28708 this.tabPanel.stripWrap.repaint();
28710 this.fireEvent("activate", this.tabPanel, this);
28714 * Returns true if this tab is the active tab.
28715 * @return {Boolean}
28717 isActive : function(){
28718 return this.tabPanel.getActiveTab() == this;
28722 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28725 this.pnode.removeClass("on");
28727 this.fireEvent("deactivate", this.tabPanel, this);
28730 hideAction : function(){
28731 this.bodyEl.hide();
28732 this.bodyEl.setStyle("position", "absolute");
28733 this.bodyEl.setLeft("-20000px");
28734 this.bodyEl.setTop("-20000px");
28737 showAction : function(){
28738 this.bodyEl.setStyle("position", "relative");
28739 this.bodyEl.setTop("");
28740 this.bodyEl.setLeft("");
28741 this.bodyEl.show();
28745 * Set the tooltip for the tab.
28746 * @param {String} tooltip The tab's tooltip
28748 setTooltip : function(text){
28749 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28750 this.textEl.dom.qtip = text;
28751 this.textEl.dom.removeAttribute('title');
28753 this.textEl.dom.title = text;
28757 onTabClick : function(e){
28758 e.preventDefault();
28759 this.tabPanel.activate(this.id);
28762 onTabMouseDown : function(e){
28763 e.preventDefault();
28764 this.tabPanel.activate(this.id);
28767 getWidth : function(){
28768 return this.inner.getWidth();
28771 setWidth : function(width){
28772 var iwidth = width - this.pnode.getPadding("lr");
28773 this.inner.setWidth(iwidth);
28774 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28775 this.pnode.setWidth(width);
28779 * Show or hide the tab
28780 * @param {Boolean} hidden True to hide or false to show.
28782 setHidden : function(hidden){
28783 this.hidden = hidden;
28784 this.pnode.setStyle("display", hidden ? "none" : "");
28788 * Returns true if this tab is "hidden"
28789 * @return {Boolean}
28791 isHidden : function(){
28792 return this.hidden;
28796 * Returns the text for this tab
28799 getText : function(){
28803 autoSize : function(){
28804 //this.el.beginMeasure();
28805 this.textEl.setWidth(1);
28807 * #2804 [new] Tabs in Roojs
28808 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28810 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28811 //this.el.endMeasure();
28815 * Sets the text for the tab (Note: this also sets the tooltip text)
28816 * @param {String} text The tab's text and tooltip
28818 setText : function(text){
28820 this.textEl.update(text);
28821 this.setTooltip(text);
28822 if(!this.tabPanel.resizeTabs){
28827 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28829 activate : function(){
28830 this.tabPanel.activate(this.id);
28834 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28836 disable : function(){
28837 if(this.tabPanel.active != this){
28838 this.disabled = true;
28839 this.pnode.addClass("disabled");
28844 * Enables this TabPanelItem if it was previously disabled.
28846 enable : function(){
28847 this.disabled = false;
28848 this.pnode.removeClass("disabled");
28852 * Sets the content for this TabPanelItem.
28853 * @param {String} content The content
28854 * @param {Boolean} loadScripts true to look for and load scripts
28856 setContent : function(content, loadScripts){
28857 this.bodyEl.update(content, loadScripts);
28861 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28862 * @return {Roo.UpdateManager} The UpdateManager
28864 getUpdateManager : function(){
28865 return this.bodyEl.getUpdateManager();
28869 * Set a URL to be used to load the content for this TabPanelItem.
28870 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28871 * @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)
28872 * @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)
28873 * @return {Roo.UpdateManager} The UpdateManager
28875 setUrl : function(url, params, loadOnce){
28876 if(this.refreshDelegate){
28877 this.un('activate', this.refreshDelegate);
28879 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28880 this.on("activate", this.refreshDelegate);
28881 return this.bodyEl.getUpdateManager();
28885 _handleRefresh : function(url, params, loadOnce){
28886 if(!loadOnce || !this.loaded){
28887 var updater = this.bodyEl.getUpdateManager();
28888 updater.update(url, params, this._setLoaded.createDelegate(this));
28893 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28894 * Will fail silently if the setUrl method has not been called.
28895 * This does not activate the panel, just updates its content.
28897 refresh : function(){
28898 if(this.refreshDelegate){
28899 this.loaded = false;
28900 this.refreshDelegate();
28905 _setLoaded : function(){
28906 this.loaded = true;
28910 closeClick : function(e){
28913 this.fireEvent("beforeclose", this, o);
28914 if(o.cancel !== true){
28915 this.tabPanel.removeTab(this.id);
28919 * The text displayed in the tooltip for the close icon.
28922 closeText : "Close this tab"
28926 Roo.TabPanel.prototype.createStrip = function(container){
28927 var strip = document.createElement("div");
28928 strip.className = "x-tabs-wrap";
28929 container.appendChild(strip);
28933 Roo.TabPanel.prototype.createStripList = function(strip){
28934 // div wrapper for retard IE
28935 // returns the "tr" element.
28936 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28937 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28938 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28939 return strip.firstChild.firstChild.firstChild.firstChild;
28942 Roo.TabPanel.prototype.createBody = function(container){
28943 var body = document.createElement("div");
28944 Roo.id(body, "tab-body");
28945 Roo.fly(body).addClass("x-tabs-body");
28946 container.appendChild(body);
28950 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28951 var body = Roo.getDom(id);
28953 body = document.createElement("div");
28956 Roo.fly(body).addClass("x-tabs-item-body");
28957 bodyEl.insertBefore(body, bodyEl.firstChild);
28961 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28962 var td = document.createElement("td");
28963 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28964 //stripEl.appendChild(td);
28966 td.className = "x-tabs-closable";
28967 if(!this.closeTpl){
28968 this.closeTpl = new Roo.Template(
28969 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28970 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28971 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28974 var el = this.closeTpl.overwrite(td, {"text": text});
28975 var close = el.getElementsByTagName("div")[0];
28976 var inner = el.getElementsByTagName("em")[0];
28977 return {"el": el, "close": close, "inner": inner};
28980 this.tabTpl = new Roo.Template(
28981 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28982 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28985 var el = this.tabTpl.overwrite(td, {"text": text});
28986 var inner = el.getElementsByTagName("em")[0];
28987 return {"el": el, "inner": inner};
28991 * Ext JS Library 1.1.1
28992 * Copyright(c) 2006-2007, Ext JS, LLC.
28994 * Originally Released Under LGPL - original licence link has changed is not relivant.
28997 * <script type="text/javascript">
29001 * @class Roo.Button
29002 * @extends Roo.util.Observable
29003 * Simple Button class
29004 * @cfg {String} text The button text
29005 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29006 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29007 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29008 * @cfg {Object} scope The scope of the handler
29009 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29010 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29011 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29012 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29013 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29014 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29015 applies if enableToggle = true)
29016 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29017 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29018 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29020 * Create a new button
29021 * @param {Object} config The config object
29023 Roo.Button = function(renderTo, config)
29027 renderTo = config.renderTo || false;
29030 Roo.apply(this, config);
29034 * Fires when this button is clicked
29035 * @param {Button} this
29036 * @param {EventObject} e The click event
29041 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29042 * @param {Button} this
29043 * @param {Boolean} pressed
29048 * Fires when the mouse hovers over the button
29049 * @param {Button} this
29050 * @param {Event} e The event object
29052 'mouseover' : true,
29055 * Fires when the mouse exits the button
29056 * @param {Button} this
29057 * @param {Event} e The event object
29062 * Fires when the button is rendered
29063 * @param {Button} this
29068 this.menu = Roo.menu.MenuMgr.get(this.menu);
29070 // register listeners first!! - so render can be captured..
29071 Roo.util.Observable.call(this);
29073 this.render(renderTo);
29079 Roo.extend(Roo.Button, Roo.util.Observable, {
29085 * Read-only. True if this button is hidden
29090 * Read-only. True if this button is disabled
29095 * Read-only. True if this button is pressed (only if enableToggle = true)
29101 * @cfg {Number} tabIndex
29102 * The DOM tabIndex for this button (defaults to undefined)
29104 tabIndex : undefined,
29107 * @cfg {Boolean} enableToggle
29108 * True to enable pressed/not pressed toggling (defaults to false)
29110 enableToggle: false,
29112 * @cfg {Mixed} menu
29113 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29117 * @cfg {String} menuAlign
29118 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29120 menuAlign : "tl-bl?",
29123 * @cfg {String} iconCls
29124 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29126 iconCls : undefined,
29128 * @cfg {String} type
29129 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29134 menuClassTarget: 'tr',
29137 * @cfg {String} clickEvent
29138 * The type of event to map to the button's event handler (defaults to 'click')
29140 clickEvent : 'click',
29143 * @cfg {Boolean} handleMouseEvents
29144 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29146 handleMouseEvents : true,
29149 * @cfg {String} tooltipType
29150 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29152 tooltipType : 'qtip',
29155 * @cfg {String} cls
29156 * A CSS class to apply to the button's main element.
29160 * @cfg {Roo.Template} template (Optional)
29161 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29162 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29163 * require code modifications if required elements (e.g. a button) aren't present.
29167 render : function(renderTo){
29169 if(this.hideParent){
29170 this.parentEl = Roo.get(renderTo);
29172 if(!this.dhconfig){
29173 if(!this.template){
29174 if(!Roo.Button.buttonTemplate){
29175 // hideous table template
29176 Roo.Button.buttonTemplate = new Roo.Template(
29177 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29178 '<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>',
29179 "</tr></tbody></table>");
29181 this.template = Roo.Button.buttonTemplate;
29183 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29184 var btnEl = btn.child("button:first");
29185 btnEl.on('focus', this.onFocus, this);
29186 btnEl.on('blur', this.onBlur, this);
29188 btn.addClass(this.cls);
29191 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29194 btnEl.addClass(this.iconCls);
29196 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29199 if(this.tabIndex !== undefined){
29200 btnEl.dom.tabIndex = this.tabIndex;
29203 if(typeof this.tooltip == 'object'){
29204 Roo.QuickTips.tips(Roo.apply({
29208 btnEl.dom[this.tooltipType] = this.tooltip;
29212 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29216 this.el.dom.id = this.el.id = this.id;
29219 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29220 this.menu.on("show", this.onMenuShow, this);
29221 this.menu.on("hide", this.onMenuHide, this);
29223 btn.addClass("x-btn");
29224 if(Roo.isIE && !Roo.isIE7){
29225 this.autoWidth.defer(1, this);
29229 if(this.handleMouseEvents){
29230 btn.on("mouseover", this.onMouseOver, this);
29231 btn.on("mouseout", this.onMouseOut, this);
29232 btn.on("mousedown", this.onMouseDown, this);
29234 btn.on(this.clickEvent, this.onClick, this);
29235 //btn.on("mouseup", this.onMouseUp, this);
29242 Roo.ButtonToggleMgr.register(this);
29244 this.el.addClass("x-btn-pressed");
29247 var repeater = new Roo.util.ClickRepeater(btn,
29248 typeof this.repeat == "object" ? this.repeat : {}
29250 repeater.on("click", this.onClick, this);
29253 this.fireEvent('render', this);
29257 * Returns the button's underlying element
29258 * @return {Roo.Element} The element
29260 getEl : function(){
29265 * Destroys this Button and removes any listeners.
29267 destroy : function(){
29268 Roo.ButtonToggleMgr.unregister(this);
29269 this.el.removeAllListeners();
29270 this.purgeListeners();
29275 autoWidth : function(){
29277 this.el.setWidth("auto");
29278 if(Roo.isIE7 && Roo.isStrict){
29279 var ib = this.el.child('button');
29280 if(ib && ib.getWidth() > 20){
29282 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29287 this.el.beginMeasure();
29289 if(this.el.getWidth() < this.minWidth){
29290 this.el.setWidth(this.minWidth);
29293 this.el.endMeasure();
29300 * Assigns this button's click handler
29301 * @param {Function} handler The function to call when the button is clicked
29302 * @param {Object} scope (optional) Scope for the function passed in
29304 setHandler : function(handler, scope){
29305 this.handler = handler;
29306 this.scope = scope;
29310 * Sets this button's text
29311 * @param {String} text The button text
29313 setText : function(text){
29316 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29322 * Gets the text for this button
29323 * @return {String} The button text
29325 getText : function(){
29333 this.hidden = false;
29335 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29343 this.hidden = true;
29345 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29350 * Convenience function for boolean show/hide
29351 * @param {Boolean} visible True to show, false to hide
29353 setVisible: function(visible){
29362 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29363 * @param {Boolean} state (optional) Force a particular state
29365 toggle : function(state){
29366 state = state === undefined ? !this.pressed : state;
29367 if(state != this.pressed){
29369 this.el.addClass("x-btn-pressed");
29370 this.pressed = true;
29371 this.fireEvent("toggle", this, true);
29373 this.el.removeClass("x-btn-pressed");
29374 this.pressed = false;
29375 this.fireEvent("toggle", this, false);
29377 if(this.toggleHandler){
29378 this.toggleHandler.call(this.scope || this, this, state);
29386 focus : function(){
29387 this.el.child('button:first').focus();
29391 * Disable this button
29393 disable : function(){
29395 this.el.addClass("x-btn-disabled");
29397 this.disabled = true;
29401 * Enable this button
29403 enable : function(){
29405 this.el.removeClass("x-btn-disabled");
29407 this.disabled = false;
29411 * Convenience function for boolean enable/disable
29412 * @param {Boolean} enabled True to enable, false to disable
29414 setDisabled : function(v){
29415 this[v !== true ? "enable" : "disable"]();
29419 onClick : function(e)
29422 e.preventDefault();
29427 if(!this.disabled){
29428 if(this.enableToggle){
29431 if(this.menu && !this.menu.isVisible()){
29432 this.menu.show(this.el, this.menuAlign);
29434 this.fireEvent("click", this, e);
29436 this.el.removeClass("x-btn-over");
29437 this.handler.call(this.scope || this, this, e);
29442 onMouseOver : function(e){
29443 if(!this.disabled){
29444 this.el.addClass("x-btn-over");
29445 this.fireEvent('mouseover', this, e);
29449 onMouseOut : function(e){
29450 if(!e.within(this.el, true)){
29451 this.el.removeClass("x-btn-over");
29452 this.fireEvent('mouseout', this, e);
29456 onFocus : function(e){
29457 if(!this.disabled){
29458 this.el.addClass("x-btn-focus");
29462 onBlur : function(e){
29463 this.el.removeClass("x-btn-focus");
29466 onMouseDown : function(e){
29467 if(!this.disabled && e.button == 0){
29468 this.el.addClass("x-btn-click");
29469 Roo.get(document).on('mouseup', this.onMouseUp, this);
29473 onMouseUp : function(e){
29475 this.el.removeClass("x-btn-click");
29476 Roo.get(document).un('mouseup', this.onMouseUp, this);
29480 onMenuShow : function(e){
29481 this.el.addClass("x-btn-menu-active");
29484 onMenuHide : function(e){
29485 this.el.removeClass("x-btn-menu-active");
29489 // Private utility class used by Button
29490 Roo.ButtonToggleMgr = function(){
29493 function toggleGroup(btn, state){
29495 var g = groups[btn.toggleGroup];
29496 for(var i = 0, l = g.length; i < l; i++){
29498 g[i].toggle(false);
29505 register : function(btn){
29506 if(!btn.toggleGroup){
29509 var g = groups[btn.toggleGroup];
29511 g = groups[btn.toggleGroup] = [];
29514 btn.on("toggle", toggleGroup);
29517 unregister : function(btn){
29518 if(!btn.toggleGroup){
29521 var g = groups[btn.toggleGroup];
29524 btn.un("toggle", toggleGroup);
29530 * Ext JS Library 1.1.1
29531 * Copyright(c) 2006-2007, Ext JS, LLC.
29533 * Originally Released Under LGPL - original licence link has changed is not relivant.
29536 * <script type="text/javascript">
29540 * @class Roo.SplitButton
29541 * @extends Roo.Button
29542 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29543 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29544 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29545 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29546 * @cfg {String} arrowTooltip The title attribute of the arrow
29548 * Create a new menu button
29549 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29550 * @param {Object} config The config object
29552 Roo.SplitButton = function(renderTo, config){
29553 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29555 * @event arrowclick
29556 * Fires when this button's arrow is clicked
29557 * @param {SplitButton} this
29558 * @param {EventObject} e The click event
29560 this.addEvents({"arrowclick":true});
29563 Roo.extend(Roo.SplitButton, Roo.Button, {
29564 render : function(renderTo){
29565 // this is one sweet looking template!
29566 var tpl = new Roo.Template(
29567 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29568 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29569 '<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>',
29570 "</tbody></table></td><td>",
29571 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29572 '<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>',
29573 "</tbody></table></td></tr></table>"
29575 var btn = tpl.append(renderTo, [this.text, this.type], true);
29576 var btnEl = btn.child("button");
29578 btn.addClass(this.cls);
29581 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29584 btnEl.addClass(this.iconCls);
29586 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29590 if(this.handleMouseEvents){
29591 btn.on("mouseover", this.onMouseOver, this);
29592 btn.on("mouseout", this.onMouseOut, this);
29593 btn.on("mousedown", this.onMouseDown, this);
29594 btn.on("mouseup", this.onMouseUp, this);
29596 btn.on(this.clickEvent, this.onClick, this);
29598 if(typeof this.tooltip == 'object'){
29599 Roo.QuickTips.tips(Roo.apply({
29603 btnEl.dom[this.tooltipType] = this.tooltip;
29606 if(this.arrowTooltip){
29607 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29616 this.el.addClass("x-btn-pressed");
29618 if(Roo.isIE && !Roo.isIE7){
29619 this.autoWidth.defer(1, this);
29624 this.menu.on("show", this.onMenuShow, this);
29625 this.menu.on("hide", this.onMenuHide, this);
29627 this.fireEvent('render', this);
29631 autoWidth : function(){
29633 var tbl = this.el.child("table:first");
29634 var tbl2 = this.el.child("table:last");
29635 this.el.setWidth("auto");
29636 tbl.setWidth("auto");
29637 if(Roo.isIE7 && Roo.isStrict){
29638 var ib = this.el.child('button:first');
29639 if(ib && ib.getWidth() > 20){
29641 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29646 this.el.beginMeasure();
29648 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29649 tbl.setWidth(this.minWidth-tbl2.getWidth());
29652 this.el.endMeasure();
29655 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29659 * Sets this button's click handler
29660 * @param {Function} handler The function to call when the button is clicked
29661 * @param {Object} scope (optional) Scope for the function passed above
29663 setHandler : function(handler, scope){
29664 this.handler = handler;
29665 this.scope = scope;
29669 * Sets this button's arrow click handler
29670 * @param {Function} handler The function to call when the arrow is clicked
29671 * @param {Object} scope (optional) Scope for the function passed above
29673 setArrowHandler : function(handler, scope){
29674 this.arrowHandler = handler;
29675 this.scope = scope;
29681 focus : function(){
29683 this.el.child("button:first").focus();
29688 onClick : function(e){
29689 e.preventDefault();
29690 if(!this.disabled){
29691 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29692 if(this.menu && !this.menu.isVisible()){
29693 this.menu.show(this.el, this.menuAlign);
29695 this.fireEvent("arrowclick", this, e);
29696 if(this.arrowHandler){
29697 this.arrowHandler.call(this.scope || this, this, e);
29700 this.fireEvent("click", this, e);
29702 this.handler.call(this.scope || this, this, e);
29708 onMouseDown : function(e){
29709 if(!this.disabled){
29710 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29714 onMouseUp : function(e){
29715 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29720 // backwards compat
29721 Roo.MenuButton = Roo.SplitButton;/*
29723 * Ext JS Library 1.1.1
29724 * Copyright(c) 2006-2007, Ext JS, LLC.
29726 * Originally Released Under LGPL - original licence link has changed is not relivant.
29729 * <script type="text/javascript">
29733 * @class Roo.Toolbar
29734 * Basic Toolbar class.
29736 * Creates a new Toolbar
29737 * @param {Object} container The config object
29739 Roo.Toolbar = function(container, buttons, config)
29741 /// old consturctor format still supported..
29742 if(container instanceof Array){ // omit the container for later rendering
29743 buttons = container;
29747 if (typeof(container) == 'object' && container.xtype) {
29748 config = container;
29749 container = config.container;
29750 buttons = config.buttons || []; // not really - use items!!
29753 if (config && config.items) {
29754 xitems = config.items;
29755 delete config.items;
29757 Roo.apply(this, config);
29758 this.buttons = buttons;
29761 this.render(container);
29763 this.xitems = xitems;
29764 Roo.each(xitems, function(b) {
29770 Roo.Toolbar.prototype = {
29772 * @cfg {Array} items
29773 * array of button configs or elements to add (will be converted to a MixedCollection)
29777 * @cfg {String/HTMLElement/Element} container
29778 * The id or element that will contain the toolbar
29781 render : function(ct){
29782 this.el = Roo.get(ct);
29784 this.el.addClass(this.cls);
29786 // using a table allows for vertical alignment
29787 // 100% width is needed by Safari...
29788 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29789 this.tr = this.el.child("tr", true);
29791 this.items = new Roo.util.MixedCollection(false, function(o){
29792 return o.id || ("item" + (++autoId));
29795 this.add.apply(this, this.buttons);
29796 delete this.buttons;
29801 * Adds element(s) to the toolbar -- this function takes a variable number of
29802 * arguments of mixed type and adds them to the toolbar.
29803 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29805 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29806 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29807 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29808 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29809 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29810 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29811 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29812 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29813 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29815 * @param {Mixed} arg2
29816 * @param {Mixed} etc.
29819 var a = arguments, l = a.length;
29820 for(var i = 0; i < l; i++){
29825 _add : function(el) {
29828 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29831 if (el.applyTo){ // some kind of form field
29832 return this.addField(el);
29834 if (el.render){ // some kind of Toolbar.Item
29835 return this.addItem(el);
29837 if (typeof el == "string"){ // string
29838 if(el == "separator" || el == "-"){
29839 return this.addSeparator();
29842 return this.addSpacer();
29845 return this.addFill();
29847 return this.addText(el);
29850 if(el.tagName){ // element
29851 return this.addElement(el);
29853 if(typeof el == "object"){ // must be button config?
29854 return this.addButton(el);
29856 // and now what?!?!
29862 * Add an Xtype element
29863 * @param {Object} xtype Xtype Object
29864 * @return {Object} created Object
29866 addxtype : function(e){
29867 return this.add(e);
29871 * Returns the Element for this toolbar.
29872 * @return {Roo.Element}
29874 getEl : function(){
29880 * @return {Roo.Toolbar.Item} The separator item
29882 addSeparator : function(){
29883 return this.addItem(new Roo.Toolbar.Separator());
29887 * Adds a spacer element
29888 * @return {Roo.Toolbar.Spacer} The spacer item
29890 addSpacer : function(){
29891 return this.addItem(new Roo.Toolbar.Spacer());
29895 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29896 * @return {Roo.Toolbar.Fill} The fill item
29898 addFill : function(){
29899 return this.addItem(new Roo.Toolbar.Fill());
29903 * Adds any standard HTML element to the toolbar
29904 * @param {String/HTMLElement/Element} el The element or id of the element to add
29905 * @return {Roo.Toolbar.Item} The element's item
29907 addElement : function(el){
29908 return this.addItem(new Roo.Toolbar.Item(el));
29911 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29912 * @type Roo.util.MixedCollection
29917 * Adds any Toolbar.Item or subclass
29918 * @param {Roo.Toolbar.Item} item
29919 * @return {Roo.Toolbar.Item} The item
29921 addItem : function(item){
29922 var td = this.nextBlock();
29924 this.items.add(item);
29929 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29930 * @param {Object/Array} config A button config or array of configs
29931 * @return {Roo.Toolbar.Button/Array}
29933 addButton : function(config){
29934 if(config instanceof Array){
29936 for(var i = 0, len = config.length; i < len; i++) {
29937 buttons.push(this.addButton(config[i]));
29942 if(!(config instanceof Roo.Toolbar.Button)){
29944 new Roo.Toolbar.SplitButton(config) :
29945 new Roo.Toolbar.Button(config);
29947 var td = this.nextBlock();
29954 * Adds text to the toolbar
29955 * @param {String} text The text to add
29956 * @return {Roo.Toolbar.Item} The element's item
29958 addText : function(text){
29959 return this.addItem(new Roo.Toolbar.TextItem(text));
29963 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29964 * @param {Number} index The index where the item is to be inserted
29965 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29966 * @return {Roo.Toolbar.Button/Item}
29968 insertButton : function(index, item){
29969 if(item instanceof Array){
29971 for(var i = 0, len = item.length; i < len; i++) {
29972 buttons.push(this.insertButton(index + i, item[i]));
29976 if (!(item instanceof Roo.Toolbar.Button)){
29977 item = new Roo.Toolbar.Button(item);
29979 var td = document.createElement("td");
29980 this.tr.insertBefore(td, this.tr.childNodes[index]);
29982 this.items.insert(index, item);
29987 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29988 * @param {Object} config
29989 * @return {Roo.Toolbar.Item} The element's item
29991 addDom : function(config, returnEl){
29992 var td = this.nextBlock();
29993 Roo.DomHelper.overwrite(td, config);
29994 var ti = new Roo.Toolbar.Item(td.firstChild);
29996 this.items.add(ti);
30001 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30002 * @type Roo.util.MixedCollection
30007 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30008 * Note: the field should not have been rendered yet. For a field that has already been
30009 * rendered, use {@link #addElement}.
30010 * @param {Roo.form.Field} field
30011 * @return {Roo.ToolbarItem}
30015 addField : function(field) {
30016 if (!this.fields) {
30018 this.fields = new Roo.util.MixedCollection(false, function(o){
30019 return o.id || ("item" + (++autoId));
30024 var td = this.nextBlock();
30026 var ti = new Roo.Toolbar.Item(td.firstChild);
30028 this.items.add(ti);
30029 this.fields.add(field);
30040 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30041 this.el.child('div').hide();
30049 this.el.child('div').show();
30053 nextBlock : function(){
30054 var td = document.createElement("td");
30055 this.tr.appendChild(td);
30060 destroy : function(){
30061 if(this.items){ // rendered?
30062 Roo.destroy.apply(Roo, this.items.items);
30064 if(this.fields){ // rendered?
30065 Roo.destroy.apply(Roo, this.fields.items);
30067 Roo.Element.uncache(this.el, this.tr);
30072 * @class Roo.Toolbar.Item
30073 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30075 * Creates a new Item
30076 * @param {HTMLElement} el
30078 Roo.Toolbar.Item = function(el){
30080 if (typeof (el.xtype) != 'undefined') {
30085 this.el = Roo.getDom(el);
30086 this.id = Roo.id(this.el);
30087 this.hidden = false;
30092 * Fires when the button is rendered
30093 * @param {Button} this
30097 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30099 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30100 //Roo.Toolbar.Item.prototype = {
30103 * Get this item's HTML Element
30104 * @return {HTMLElement}
30106 getEl : function(){
30111 render : function(td){
30114 td.appendChild(this.el);
30116 this.fireEvent('render', this);
30120 * Removes and destroys this item.
30122 destroy : function(){
30123 this.td.parentNode.removeChild(this.td);
30130 this.hidden = false;
30131 this.td.style.display = "";
30138 this.hidden = true;
30139 this.td.style.display = "none";
30143 * Convenience function for boolean show/hide.
30144 * @param {Boolean} visible true to show/false to hide
30146 setVisible: function(visible){
30155 * Try to focus this item.
30157 focus : function(){
30158 Roo.fly(this.el).focus();
30162 * Disables this item.
30164 disable : function(){
30165 Roo.fly(this.td).addClass("x-item-disabled");
30166 this.disabled = true;
30167 this.el.disabled = true;
30171 * Enables this item.
30173 enable : function(){
30174 Roo.fly(this.td).removeClass("x-item-disabled");
30175 this.disabled = false;
30176 this.el.disabled = false;
30182 * @class Roo.Toolbar.Separator
30183 * @extends Roo.Toolbar.Item
30184 * A simple toolbar separator class
30186 * Creates a new Separator
30188 Roo.Toolbar.Separator = function(cfg){
30190 var s = document.createElement("span");
30191 s.className = "ytb-sep";
30196 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30198 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30199 enable:Roo.emptyFn,
30200 disable:Roo.emptyFn,
30205 * @class Roo.Toolbar.Spacer
30206 * @extends Roo.Toolbar.Item
30207 * A simple element that adds extra horizontal space to a toolbar.
30209 * Creates a new Spacer
30211 Roo.Toolbar.Spacer = function(cfg){
30212 var s = document.createElement("div");
30213 s.className = "ytb-spacer";
30217 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30219 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30220 enable:Roo.emptyFn,
30221 disable:Roo.emptyFn,
30226 * @class Roo.Toolbar.Fill
30227 * @extends Roo.Toolbar.Spacer
30228 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30230 * Creates a new Spacer
30232 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30234 render : function(td){
30235 td.style.width = '100%';
30236 Roo.Toolbar.Fill.superclass.render.call(this, td);
30241 * @class Roo.Toolbar.TextItem
30242 * @extends Roo.Toolbar.Item
30243 * A simple class that renders text directly into a toolbar.
30245 * Creates a new TextItem
30246 * @param {String} text
30248 Roo.Toolbar.TextItem = function(cfg){
30249 var text = cfg || "";
30250 if (typeof(cfg) == 'object') {
30251 text = cfg.text || "";
30255 var s = document.createElement("span");
30256 s.className = "ytb-text";
30257 s.innerHTML = text;
30262 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30264 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30267 enable:Roo.emptyFn,
30268 disable:Roo.emptyFn,
30273 * @class Roo.Toolbar.Button
30274 * @extends Roo.Button
30275 * A button that renders into a toolbar.
30277 * Creates a new Button
30278 * @param {Object} config A standard {@link Roo.Button} config object
30280 Roo.Toolbar.Button = function(config){
30281 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30283 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30284 render : function(td){
30286 Roo.Toolbar.Button.superclass.render.call(this, td);
30290 * Removes and destroys this button
30292 destroy : function(){
30293 Roo.Toolbar.Button.superclass.destroy.call(this);
30294 this.td.parentNode.removeChild(this.td);
30298 * Shows this button
30301 this.hidden = false;
30302 this.td.style.display = "";
30306 * Hides this button
30309 this.hidden = true;
30310 this.td.style.display = "none";
30314 * Disables this item
30316 disable : function(){
30317 Roo.fly(this.td).addClass("x-item-disabled");
30318 this.disabled = true;
30322 * Enables this item
30324 enable : function(){
30325 Roo.fly(this.td).removeClass("x-item-disabled");
30326 this.disabled = false;
30329 // backwards compat
30330 Roo.ToolbarButton = Roo.Toolbar.Button;
30333 * @class Roo.Toolbar.SplitButton
30334 * @extends Roo.SplitButton
30335 * A menu button that renders into a toolbar.
30337 * Creates a new SplitButton
30338 * @param {Object} config A standard {@link Roo.SplitButton} config object
30340 Roo.Toolbar.SplitButton = function(config){
30341 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30343 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30344 render : function(td){
30346 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30350 * Removes and destroys this button
30352 destroy : function(){
30353 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30354 this.td.parentNode.removeChild(this.td);
30358 * Shows this button
30361 this.hidden = false;
30362 this.td.style.display = "";
30366 * Hides this button
30369 this.hidden = true;
30370 this.td.style.display = "none";
30374 // backwards compat
30375 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30377 * Ext JS Library 1.1.1
30378 * Copyright(c) 2006-2007, Ext JS, LLC.
30380 * Originally Released Under LGPL - original licence link has changed is not relivant.
30383 * <script type="text/javascript">
30387 * @class Roo.PagingToolbar
30388 * @extends Roo.Toolbar
30389 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30391 * Create a new PagingToolbar
30392 * @param {Object} config The config object
30394 Roo.PagingToolbar = function(el, ds, config)
30396 // old args format still supported... - xtype is prefered..
30397 if (typeof(el) == 'object' && el.xtype) {
30398 // created from xtype...
30400 ds = el.dataSource;
30401 el = config.container;
30404 if (config.items) {
30405 items = config.items;
30409 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30412 this.renderButtons(this.el);
30415 // supprot items array.
30417 Roo.each(items, function(e) {
30418 this.add(Roo.factory(e));
30423 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30425 * @cfg {Roo.data.Store} dataSource
30426 * The underlying data store providing the paged data
30429 * @cfg {String/HTMLElement/Element} container
30430 * container The id or element that will contain the toolbar
30433 * @cfg {Boolean} displayInfo
30434 * True to display the displayMsg (defaults to false)
30437 * @cfg {Number} pageSize
30438 * The number of records to display per page (defaults to 20)
30442 * @cfg {String} displayMsg
30443 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30445 displayMsg : 'Displaying {0} - {1} of {2}',
30447 * @cfg {String} emptyMsg
30448 * The message to display when no records are found (defaults to "No data to display")
30450 emptyMsg : 'No data to display',
30452 * Customizable piece of the default paging text (defaults to "Page")
30455 beforePageText : "Page",
30457 * Customizable piece of the default paging text (defaults to "of %0")
30460 afterPageText : "of {0}",
30462 * Customizable piece of the default paging text (defaults to "First Page")
30465 firstText : "First Page",
30467 * Customizable piece of the default paging text (defaults to "Previous Page")
30470 prevText : "Previous Page",
30472 * Customizable piece of the default paging text (defaults to "Next Page")
30475 nextText : "Next Page",
30477 * Customizable piece of the default paging text (defaults to "Last Page")
30480 lastText : "Last Page",
30482 * Customizable piece of the default paging text (defaults to "Refresh")
30485 refreshText : "Refresh",
30488 renderButtons : function(el){
30489 Roo.PagingToolbar.superclass.render.call(this, el);
30490 this.first = this.addButton({
30491 tooltip: this.firstText,
30492 cls: "x-btn-icon x-grid-page-first",
30494 handler: this.onClick.createDelegate(this, ["first"])
30496 this.prev = this.addButton({
30497 tooltip: this.prevText,
30498 cls: "x-btn-icon x-grid-page-prev",
30500 handler: this.onClick.createDelegate(this, ["prev"])
30502 //this.addSeparator();
30503 this.add(this.beforePageText);
30504 this.field = Roo.get(this.addDom({
30509 cls: "x-grid-page-number"
30511 this.field.on("keydown", this.onPagingKeydown, this);
30512 this.field.on("focus", function(){this.dom.select();});
30513 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30514 this.field.setHeight(18);
30515 //this.addSeparator();
30516 this.next = this.addButton({
30517 tooltip: this.nextText,
30518 cls: "x-btn-icon x-grid-page-next",
30520 handler: this.onClick.createDelegate(this, ["next"])
30522 this.last = this.addButton({
30523 tooltip: this.lastText,
30524 cls: "x-btn-icon x-grid-page-last",
30526 handler: this.onClick.createDelegate(this, ["last"])
30528 //this.addSeparator();
30529 this.loading = this.addButton({
30530 tooltip: this.refreshText,
30531 cls: "x-btn-icon x-grid-loading",
30532 handler: this.onClick.createDelegate(this, ["refresh"])
30535 if(this.displayInfo){
30536 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30541 updateInfo : function(){
30542 if(this.displayEl){
30543 var count = this.ds.getCount();
30544 var msg = count == 0 ?
30548 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30550 this.displayEl.update(msg);
30555 onLoad : function(ds, r, o){
30556 this.cursor = o.params ? o.params.start : 0;
30557 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30559 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30560 this.field.dom.value = ap;
30561 this.first.setDisabled(ap == 1);
30562 this.prev.setDisabled(ap == 1);
30563 this.next.setDisabled(ap == ps);
30564 this.last.setDisabled(ap == ps);
30565 this.loading.enable();
30570 getPageData : function(){
30571 var total = this.ds.getTotalCount();
30574 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30575 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30580 onLoadError : function(){
30581 this.loading.enable();
30585 onPagingKeydown : function(e){
30586 var k = e.getKey();
30587 var d = this.getPageData();
30589 var v = this.field.dom.value, pageNum;
30590 if(!v || isNaN(pageNum = parseInt(v, 10))){
30591 this.field.dom.value = d.activePage;
30594 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30595 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30598 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))
30600 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30601 this.field.dom.value = pageNum;
30602 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30605 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30607 var v = this.field.dom.value, pageNum;
30608 var increment = (e.shiftKey) ? 10 : 1;
30609 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30612 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30613 this.field.dom.value = d.activePage;
30616 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30618 this.field.dom.value = parseInt(v, 10) + increment;
30619 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30620 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30627 beforeLoad : function(){
30629 this.loading.disable();
30634 onClick : function(which){
30638 ds.load({params:{start: 0, limit: this.pageSize}});
30641 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30644 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30647 var total = ds.getTotalCount();
30648 var extra = total % this.pageSize;
30649 var lastStart = extra ? (total - extra) : total-this.pageSize;
30650 ds.load({params:{start: lastStart, limit: this.pageSize}});
30653 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30659 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30660 * @param {Roo.data.Store} store The data store to unbind
30662 unbind : function(ds){
30663 ds.un("beforeload", this.beforeLoad, this);
30664 ds.un("load", this.onLoad, this);
30665 ds.un("loadexception", this.onLoadError, this);
30666 ds.un("remove", this.updateInfo, this);
30667 ds.un("add", this.updateInfo, this);
30668 this.ds = undefined;
30672 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30673 * @param {Roo.data.Store} store The data store to bind
30675 bind : function(ds){
30676 ds.on("beforeload", this.beforeLoad, this);
30677 ds.on("load", this.onLoad, this);
30678 ds.on("loadexception", this.onLoadError, this);
30679 ds.on("remove", this.updateInfo, this);
30680 ds.on("add", this.updateInfo, this);
30685 * Ext JS Library 1.1.1
30686 * Copyright(c) 2006-2007, Ext JS, LLC.
30688 * Originally Released Under LGPL - original licence link has changed is not relivant.
30691 * <script type="text/javascript">
30695 * @class Roo.Resizable
30696 * @extends Roo.util.Observable
30697 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30698 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30699 * 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
30700 * the element will be wrapped for you automatically.</p>
30701 * <p>Here is the list of valid resize handles:</p>
30704 ------ -------------------
30713 'hd' horizontal drag
30716 * <p>Here's an example showing the creation of a typical Resizable:</p>
30718 var resizer = new Roo.Resizable("element-id", {
30726 resizer.on("resize", myHandler);
30728 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30729 * resizer.east.setDisplayed(false);</p>
30730 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30731 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30732 * resize operation's new size (defaults to [0, 0])
30733 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30734 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30735 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30736 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30737 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30738 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30739 * @cfg {Number} width The width of the element in pixels (defaults to null)
30740 * @cfg {Number} height The height of the element in pixels (defaults to null)
30741 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30742 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30743 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30744 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30745 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30746 * in favor of the handles config option (defaults to false)
30747 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30748 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30749 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30750 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30751 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30752 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30753 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30754 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30755 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30756 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30757 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30759 * Create a new resizable component
30760 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30761 * @param {Object} config configuration options
30763 Roo.Resizable = function(el, config)
30765 this.el = Roo.get(el);
30767 if(config && config.wrap){
30768 config.resizeChild = this.el;
30769 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30770 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30771 this.el.setStyle("overflow", "hidden");
30772 this.el.setPositioning(config.resizeChild.getPositioning());
30773 config.resizeChild.clearPositioning();
30774 if(!config.width || !config.height){
30775 var csize = config.resizeChild.getSize();
30776 this.el.setSize(csize.width, csize.height);
30778 if(config.pinned && !config.adjustments){
30779 config.adjustments = "auto";
30783 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30784 this.proxy.unselectable();
30785 this.proxy.enableDisplayMode('block');
30787 Roo.apply(this, config);
30790 this.disableTrackOver = true;
30791 this.el.addClass("x-resizable-pinned");
30793 // if the element isn't positioned, make it relative
30794 var position = this.el.getStyle("position");
30795 if(position != "absolute" && position != "fixed"){
30796 this.el.setStyle("position", "relative");
30798 if(!this.handles){ // no handles passed, must be legacy style
30799 this.handles = 's,e,se';
30800 if(this.multiDirectional){
30801 this.handles += ',n,w';
30804 if(this.handles == "all"){
30805 this.handles = "n s e w ne nw se sw";
30807 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30808 var ps = Roo.Resizable.positions;
30809 for(var i = 0, len = hs.length; i < len; i++){
30810 if(hs[i] && ps[hs[i]]){
30811 var pos = ps[hs[i]];
30812 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30816 this.corner = this.southeast;
30818 // updateBox = the box can move..
30819 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30820 this.updateBox = true;
30823 this.activeHandle = null;
30825 if(this.resizeChild){
30826 if(typeof this.resizeChild == "boolean"){
30827 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30829 this.resizeChild = Roo.get(this.resizeChild, true);
30833 if(this.adjustments == "auto"){
30834 var rc = this.resizeChild;
30835 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30836 if(rc && (hw || hn)){
30837 rc.position("relative");
30838 rc.setLeft(hw ? hw.el.getWidth() : 0);
30839 rc.setTop(hn ? hn.el.getHeight() : 0);
30841 this.adjustments = [
30842 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30843 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30847 if(this.draggable){
30848 this.dd = this.dynamic ?
30849 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30850 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30856 * @event beforeresize
30857 * Fired before resize is allowed. Set enabled to false to cancel resize.
30858 * @param {Roo.Resizable} this
30859 * @param {Roo.EventObject} e The mousedown event
30861 "beforeresize" : true,
30864 * Fired a resizing.
30865 * @param {Roo.Resizable} this
30866 * @param {Number} x The new x position
30867 * @param {Number} y The new y position
30868 * @param {Number} w The new w width
30869 * @param {Number} h The new h hight
30870 * @param {Roo.EventObject} e The mouseup event
30875 * Fired after a resize.
30876 * @param {Roo.Resizable} this
30877 * @param {Number} width The new width
30878 * @param {Number} height The new height
30879 * @param {Roo.EventObject} e The mouseup event
30884 if(this.width !== null && this.height !== null){
30885 this.resizeTo(this.width, this.height);
30887 this.updateChildSize();
30890 this.el.dom.style.zoom = 1;
30892 Roo.Resizable.superclass.constructor.call(this);
30895 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30896 resizeChild : false,
30897 adjustments : [0, 0],
30907 multiDirectional : false,
30908 disableTrackOver : false,
30909 easing : 'easeOutStrong',
30910 widthIncrement : 0,
30911 heightIncrement : 0,
30915 preserveRatio : false,
30916 transparent: false,
30922 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30924 constrainTo: undefined,
30926 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30928 resizeRegion: undefined,
30932 * Perform a manual resize
30933 * @param {Number} width
30934 * @param {Number} height
30936 resizeTo : function(width, height){
30937 this.el.setSize(width, height);
30938 this.updateChildSize();
30939 this.fireEvent("resize", this, width, height, null);
30943 startSizing : function(e, handle){
30944 this.fireEvent("beforeresize", this, e);
30945 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30948 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30949 this.overlay.unselectable();
30950 this.overlay.enableDisplayMode("block");
30951 this.overlay.on("mousemove", this.onMouseMove, this);
30952 this.overlay.on("mouseup", this.onMouseUp, this);
30954 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30956 this.resizing = true;
30957 this.startBox = this.el.getBox();
30958 this.startPoint = e.getXY();
30959 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30960 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30962 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30963 this.overlay.show();
30965 if(this.constrainTo) {
30966 var ct = Roo.get(this.constrainTo);
30967 this.resizeRegion = ct.getRegion().adjust(
30968 ct.getFrameWidth('t'),
30969 ct.getFrameWidth('l'),
30970 -ct.getFrameWidth('b'),
30971 -ct.getFrameWidth('r')
30975 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30977 this.proxy.setBox(this.startBox);
30979 this.proxy.setStyle('visibility', 'visible');
30985 onMouseDown : function(handle, e){
30988 this.activeHandle = handle;
30989 this.startSizing(e, handle);
30994 onMouseUp : function(e){
30995 var size = this.resizeElement();
30996 this.resizing = false;
30998 this.overlay.hide();
31000 this.fireEvent("resize", this, size.width, size.height, e);
31004 updateChildSize : function(){
31006 if(this.resizeChild){
31008 var child = this.resizeChild;
31009 var adj = this.adjustments;
31010 if(el.dom.offsetWidth){
31011 var b = el.getSize(true);
31012 child.setSize(b.width+adj[0], b.height+adj[1]);
31014 // Second call here for IE
31015 // The first call enables instant resizing and
31016 // the second call corrects scroll bars if they
31019 setTimeout(function(){
31020 if(el.dom.offsetWidth){
31021 var b = el.getSize(true);
31022 child.setSize(b.width+adj[0], b.height+adj[1]);
31030 snap : function(value, inc, min){
31031 if(!inc || !value) {
31034 var newValue = value;
31035 var m = value % inc;
31038 newValue = value + (inc-m);
31040 newValue = value - m;
31043 return Math.max(min, newValue);
31047 resizeElement : function(){
31048 var box = this.proxy.getBox();
31049 if(this.updateBox){
31050 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31052 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31054 this.updateChildSize();
31062 constrain : function(v, diff, m, mx){
31065 }else if(v - diff > mx){
31072 onMouseMove : function(e){
31075 try{// try catch so if something goes wrong the user doesn't get hung
31077 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31081 //var curXY = this.startPoint;
31082 var curSize = this.curSize || this.startBox;
31083 var x = this.startBox.x, y = this.startBox.y;
31084 var ox = x, oy = y;
31085 var w = curSize.width, h = curSize.height;
31086 var ow = w, oh = h;
31087 var mw = this.minWidth, mh = this.minHeight;
31088 var mxw = this.maxWidth, mxh = this.maxHeight;
31089 var wi = this.widthIncrement;
31090 var hi = this.heightIncrement;
31092 var eventXY = e.getXY();
31093 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31094 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31096 var pos = this.activeHandle.position;
31101 w = Math.min(Math.max(mw, w), mxw);
31106 h = Math.min(Math.max(mh, h), mxh);
31111 w = Math.min(Math.max(mw, w), mxw);
31112 h = Math.min(Math.max(mh, h), mxh);
31115 diffY = this.constrain(h, diffY, mh, mxh);
31122 var adiffX = Math.abs(diffX);
31123 var sub = (adiffX % wi); // how much
31124 if (sub > (wi/2)) { // far enough to snap
31125 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31127 // remove difference..
31128 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31132 x = Math.max(this.minX, x);
31135 diffX = this.constrain(w, diffX, mw, mxw);
31141 w = Math.min(Math.max(mw, w), mxw);
31142 diffY = this.constrain(h, diffY, mh, mxh);
31147 diffX = this.constrain(w, diffX, mw, mxw);
31148 diffY = this.constrain(h, diffY, mh, mxh);
31155 diffX = this.constrain(w, diffX, mw, mxw);
31157 h = Math.min(Math.max(mh, h), mxh);
31163 var sw = this.snap(w, wi, mw);
31164 var sh = this.snap(h, hi, mh);
31165 if(sw != w || sh != h){
31188 if(this.preserveRatio){
31193 h = Math.min(Math.max(mh, h), mxh);
31198 w = Math.min(Math.max(mw, w), mxw);
31203 w = Math.min(Math.max(mw, w), mxw);
31209 w = Math.min(Math.max(mw, w), mxw);
31215 h = Math.min(Math.max(mh, h), mxh);
31223 h = Math.min(Math.max(mh, h), mxh);
31233 h = Math.min(Math.max(mh, h), mxh);
31241 if (pos == 'hdrag') {
31244 this.proxy.setBounds(x, y, w, h);
31246 this.resizeElement();
31250 this.fireEvent("resizing", this, x, y, w, h, e);
31254 handleOver : function(){
31256 this.el.addClass("x-resizable-over");
31261 handleOut : function(){
31262 if(!this.resizing){
31263 this.el.removeClass("x-resizable-over");
31268 * Returns the element this component is bound to.
31269 * @return {Roo.Element}
31271 getEl : function(){
31276 * Returns the resizeChild element (or null).
31277 * @return {Roo.Element}
31279 getResizeChild : function(){
31280 return this.resizeChild;
31282 groupHandler : function()
31287 * Destroys this resizable. If the element was wrapped and
31288 * removeEl is not true then the element remains.
31289 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31291 destroy : function(removeEl){
31292 this.proxy.remove();
31294 this.overlay.removeAllListeners();
31295 this.overlay.remove();
31297 var ps = Roo.Resizable.positions;
31299 if(typeof ps[k] != "function" && this[ps[k]]){
31300 var h = this[ps[k]];
31301 h.el.removeAllListeners();
31306 this.el.update("");
31313 // hash to map config positions to true positions
31314 Roo.Resizable.positions = {
31315 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31320 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31322 // only initialize the template if resizable is used
31323 var tpl = Roo.DomHelper.createTemplate(
31324 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31327 Roo.Resizable.Handle.prototype.tpl = tpl;
31329 this.position = pos;
31331 // show north drag fro topdra
31332 var handlepos = pos == 'hdrag' ? 'north' : pos;
31334 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31335 if (pos == 'hdrag') {
31336 this.el.setStyle('cursor', 'pointer');
31338 this.el.unselectable();
31340 this.el.setOpacity(0);
31342 this.el.on("mousedown", this.onMouseDown, this);
31343 if(!disableTrackOver){
31344 this.el.on("mouseover", this.onMouseOver, this);
31345 this.el.on("mouseout", this.onMouseOut, this);
31350 Roo.Resizable.Handle.prototype = {
31351 afterResize : function(rz){
31356 onMouseDown : function(e){
31357 this.rz.onMouseDown(this, e);
31360 onMouseOver : function(e){
31361 this.rz.handleOver(this, e);
31364 onMouseOut : function(e){
31365 this.rz.handleOut(this, e);
31369 * Ext JS Library 1.1.1
31370 * Copyright(c) 2006-2007, Ext JS, LLC.
31372 * Originally Released Under LGPL - original licence link has changed is not relivant.
31375 * <script type="text/javascript">
31379 * @class Roo.Editor
31380 * @extends Roo.Component
31381 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31383 * Create a new Editor
31384 * @param {Roo.form.Field} field The Field object (or descendant)
31385 * @param {Object} config The config object
31387 Roo.Editor = function(field, config){
31388 Roo.Editor.superclass.constructor.call(this, config);
31389 this.field = field;
31392 * @event beforestartedit
31393 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31394 * false from the handler of this event.
31395 * @param {Editor} this
31396 * @param {Roo.Element} boundEl The underlying element bound to this editor
31397 * @param {Mixed} value The field value being set
31399 "beforestartedit" : true,
31402 * Fires when this editor is displayed
31403 * @param {Roo.Element} boundEl The underlying element bound to this editor
31404 * @param {Mixed} value The starting field value
31406 "startedit" : true,
31408 * @event beforecomplete
31409 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31410 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31411 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31412 * event will not fire since no edit actually occurred.
31413 * @param {Editor} this
31414 * @param {Mixed} value The current field value
31415 * @param {Mixed} startValue The original field value
31417 "beforecomplete" : true,
31420 * Fires after editing is complete and any changed value has been written to the underlying field.
31421 * @param {Editor} this
31422 * @param {Mixed} value The current field value
31423 * @param {Mixed} startValue The original field value
31427 * @event specialkey
31428 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31429 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31430 * @param {Roo.form.Field} this
31431 * @param {Roo.EventObject} e The event object
31433 "specialkey" : true
31437 Roo.extend(Roo.Editor, Roo.Component, {
31439 * @cfg {Boolean/String} autosize
31440 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31441 * or "height" to adopt the height only (defaults to false)
31444 * @cfg {Boolean} revertInvalid
31445 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31446 * validation fails (defaults to true)
31449 * @cfg {Boolean} ignoreNoChange
31450 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31451 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31452 * will never be ignored.
31455 * @cfg {Boolean} hideEl
31456 * False to keep the bound element visible while the editor is displayed (defaults to true)
31459 * @cfg {Mixed} value
31460 * The data value of the underlying field (defaults to "")
31464 * @cfg {String} alignment
31465 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31469 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31470 * for bottom-right shadow (defaults to "frame")
31474 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31478 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31480 completeOnEnter : false,
31482 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31484 cancelOnEsc : false,
31486 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31491 onRender : function(ct, position){
31492 this.el = new Roo.Layer({
31493 shadow: this.shadow,
31499 constrain: this.constrain
31501 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31502 if(this.field.msgTarget != 'title'){
31503 this.field.msgTarget = 'qtip';
31505 this.field.render(this.el);
31507 this.field.el.dom.setAttribute('autocomplete', 'off');
31509 this.field.on("specialkey", this.onSpecialKey, this);
31510 if(this.swallowKeys){
31511 this.field.el.swallowEvent(['keydown','keypress']);
31514 this.field.on("blur", this.onBlur, this);
31515 if(this.field.grow){
31516 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31520 onSpecialKey : function(field, e)
31522 //Roo.log('editor onSpecialKey');
31523 if(this.completeOnEnter && e.getKey() == e.ENTER){
31525 this.completeEdit();
31528 // do not fire special key otherwise it might hide close the editor...
31529 if(e.getKey() == e.ENTER){
31532 if(this.cancelOnEsc && e.getKey() == e.ESC){
31536 this.fireEvent('specialkey', field, e);
31541 * Starts the editing process and shows the editor.
31542 * @param {String/HTMLElement/Element} el The element to edit
31543 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31544 * to the innerHTML of el.
31546 startEdit : function(el, value){
31548 this.completeEdit();
31550 this.boundEl = Roo.get(el);
31551 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31552 if(!this.rendered){
31553 this.render(this.parentEl || document.body);
31555 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31558 this.startValue = v;
31559 this.field.setValue(v);
31561 var sz = this.boundEl.getSize();
31562 switch(this.autoSize){
31564 this.setSize(sz.width, "");
31567 this.setSize("", sz.height);
31570 this.setSize(sz.width, sz.height);
31573 this.el.alignTo(this.boundEl, this.alignment);
31574 this.editing = true;
31576 Roo.QuickTips.disable();
31582 * Sets the height and width of this editor.
31583 * @param {Number} width The new width
31584 * @param {Number} height The new height
31586 setSize : function(w, h){
31587 this.field.setSize(w, h);
31594 * Realigns the editor to the bound field based on the current alignment config value.
31596 realign : function(){
31597 this.el.alignTo(this.boundEl, this.alignment);
31601 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31602 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31604 completeEdit : function(remainVisible){
31608 var v = this.getValue();
31609 if(this.revertInvalid !== false && !this.field.isValid()){
31610 v = this.startValue;
31611 this.cancelEdit(true);
31613 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31614 this.editing = false;
31618 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31619 this.editing = false;
31620 if(this.updateEl && this.boundEl){
31621 this.boundEl.update(v);
31623 if(remainVisible !== true){
31626 this.fireEvent("complete", this, v, this.startValue);
31631 onShow : function(){
31633 if(this.hideEl !== false){
31634 this.boundEl.hide();
31637 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31638 this.fixIEFocus = true;
31639 this.deferredFocus.defer(50, this);
31641 this.field.focus();
31643 this.fireEvent("startedit", this.boundEl, this.startValue);
31646 deferredFocus : function(){
31648 this.field.focus();
31653 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31654 * reverted to the original starting value.
31655 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31656 * cancel (defaults to false)
31658 cancelEdit : function(remainVisible){
31660 this.setValue(this.startValue);
31661 if(remainVisible !== true){
31668 onBlur : function(){
31669 if(this.allowBlur !== true && this.editing){
31670 this.completeEdit();
31675 onHide : function(){
31677 this.completeEdit();
31681 if(this.field.collapse){
31682 this.field.collapse();
31685 if(this.hideEl !== false){
31686 this.boundEl.show();
31689 Roo.QuickTips.enable();
31694 * Sets the data value of the editor
31695 * @param {Mixed} value Any valid value supported by the underlying field
31697 setValue : function(v){
31698 this.field.setValue(v);
31702 * Gets the data value of the editor
31703 * @return {Mixed} The data value
31705 getValue : function(){
31706 return this.field.getValue();
31710 * Ext JS Library 1.1.1
31711 * Copyright(c) 2006-2007, Ext JS, LLC.
31713 * Originally Released Under LGPL - original licence link has changed is not relivant.
31716 * <script type="text/javascript">
31720 * @class Roo.BasicDialog
31721 * @extends Roo.util.Observable
31722 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31724 var dlg = new Roo.BasicDialog("my-dlg", {
31733 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31734 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31735 dlg.addButton('Cancel', dlg.hide, dlg);
31738 <b>A Dialog should always be a direct child of the body element.</b>
31739 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31740 * @cfg {String} title Default text to display in the title bar (defaults to null)
31741 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31742 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31743 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31744 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31745 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31746 * (defaults to null with no animation)
31747 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31748 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31749 * property for valid values (defaults to 'all')
31750 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31751 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31752 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31753 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31754 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31755 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31756 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31757 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31758 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31759 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31760 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31761 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31762 * draggable = true (defaults to false)
31763 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31764 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31765 * shadow (defaults to false)
31766 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31767 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31768 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31769 * @cfg {Array} buttons Array of buttons
31770 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31772 * Create a new BasicDialog.
31773 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31774 * @param {Object} config Configuration options
31776 Roo.BasicDialog = function(el, config){
31777 this.el = Roo.get(el);
31778 var dh = Roo.DomHelper;
31779 if(!this.el && config && config.autoCreate){
31780 if(typeof config.autoCreate == "object"){
31781 if(!config.autoCreate.id){
31782 config.autoCreate.id = el;
31784 this.el = dh.append(document.body,
31785 config.autoCreate, true);
31787 this.el = dh.append(document.body,
31788 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31792 el.setDisplayed(true);
31793 el.hide = this.hideAction;
31795 el.addClass("x-dlg");
31797 Roo.apply(this, config);
31799 this.proxy = el.createProxy("x-dlg-proxy");
31800 this.proxy.hide = this.hideAction;
31801 this.proxy.setOpacity(.5);
31805 el.setWidth(config.width);
31808 el.setHeight(config.height);
31810 this.size = el.getSize();
31811 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31812 this.xy = [config.x,config.y];
31814 this.xy = el.getCenterXY(true);
31816 /** The header element @type Roo.Element */
31817 this.header = el.child("> .x-dlg-hd");
31818 /** The body element @type Roo.Element */
31819 this.body = el.child("> .x-dlg-bd");
31820 /** The footer element @type Roo.Element */
31821 this.footer = el.child("> .x-dlg-ft");
31824 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31827 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31830 this.header.unselectable();
31832 this.header.update(this.title);
31834 // this element allows the dialog to be focused for keyboard event
31835 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31836 this.focusEl.swallowEvent("click", true);
31838 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31840 // wrap the body and footer for special rendering
31841 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31843 this.bwrap.dom.appendChild(this.footer.dom);
31846 this.bg = this.el.createChild({
31847 tag: "div", cls:"x-dlg-bg",
31848 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31850 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31853 if(this.autoScroll !== false && !this.autoTabs){
31854 this.body.setStyle("overflow", "auto");
31857 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31859 if(this.closable !== false){
31860 this.el.addClass("x-dlg-closable");
31861 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31862 this.close.on("click", this.closeClick, this);
31863 this.close.addClassOnOver("x-dlg-close-over");
31865 if(this.collapsible !== false){
31866 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31867 this.collapseBtn.on("click", this.collapseClick, this);
31868 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31869 this.header.on("dblclick", this.collapseClick, this);
31871 if(this.resizable !== false){
31872 this.el.addClass("x-dlg-resizable");
31873 this.resizer = new Roo.Resizable(el, {
31874 minWidth: this.minWidth || 80,
31875 minHeight:this.minHeight || 80,
31876 handles: this.resizeHandles || "all",
31879 this.resizer.on("beforeresize", this.beforeResize, this);
31880 this.resizer.on("resize", this.onResize, this);
31882 if(this.draggable !== false){
31883 el.addClass("x-dlg-draggable");
31884 if (!this.proxyDrag) {
31885 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31888 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31890 dd.setHandleElId(this.header.id);
31891 dd.endDrag = this.endMove.createDelegate(this);
31892 dd.startDrag = this.startMove.createDelegate(this);
31893 dd.onDrag = this.onDrag.createDelegate(this);
31898 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31899 this.mask.enableDisplayMode("block");
31901 this.el.addClass("x-dlg-modal");
31904 this.shadow = new Roo.Shadow({
31905 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31906 offset : this.shadowOffset
31909 this.shadowOffset = 0;
31911 if(Roo.useShims && this.shim !== false){
31912 this.shim = this.el.createShim();
31913 this.shim.hide = this.hideAction;
31921 if (this.buttons) {
31922 var bts= this.buttons;
31924 Roo.each(bts, function(b) {
31933 * Fires when a key is pressed
31934 * @param {Roo.BasicDialog} this
31935 * @param {Roo.EventObject} e
31940 * Fires when this dialog is moved by the user.
31941 * @param {Roo.BasicDialog} this
31942 * @param {Number} x The new page X
31943 * @param {Number} y The new page Y
31948 * Fires when this dialog is resized by the user.
31949 * @param {Roo.BasicDialog} this
31950 * @param {Number} width The new width
31951 * @param {Number} height The new height
31955 * @event beforehide
31956 * Fires before this dialog is hidden.
31957 * @param {Roo.BasicDialog} this
31959 "beforehide" : true,
31962 * Fires when this dialog is hidden.
31963 * @param {Roo.BasicDialog} this
31967 * @event beforeshow
31968 * Fires before this dialog is shown.
31969 * @param {Roo.BasicDialog} this
31971 "beforeshow" : true,
31974 * Fires when this dialog is shown.
31975 * @param {Roo.BasicDialog} this
31979 el.on("keydown", this.onKeyDown, this);
31980 el.on("mousedown", this.toFront, this);
31981 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31983 Roo.DialogManager.register(this);
31984 Roo.BasicDialog.superclass.constructor.call(this);
31987 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31988 shadowOffset: Roo.isIE ? 6 : 5,
31991 minButtonWidth: 75,
31992 defaultButton: null,
31993 buttonAlign: "right",
31998 * Sets the dialog title text
31999 * @param {String} text The title text to display
32000 * @return {Roo.BasicDialog} this
32002 setTitle : function(text){
32003 this.header.update(text);
32008 closeClick : function(){
32013 collapseClick : function(){
32014 this[this.collapsed ? "expand" : "collapse"]();
32018 * Collapses the dialog to its minimized state (only the title bar is visible).
32019 * Equivalent to the user clicking the collapse dialog button.
32021 collapse : function(){
32022 if(!this.collapsed){
32023 this.collapsed = true;
32024 this.el.addClass("x-dlg-collapsed");
32025 this.restoreHeight = this.el.getHeight();
32026 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32031 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32032 * clicking the expand dialog button.
32034 expand : function(){
32035 if(this.collapsed){
32036 this.collapsed = false;
32037 this.el.removeClass("x-dlg-collapsed");
32038 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32043 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32044 * @return {Roo.TabPanel} The tabs component
32046 initTabs : function(){
32047 var tabs = this.getTabs();
32048 while(tabs.getTab(0)){
32051 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32053 tabs.addTab(Roo.id(dom), dom.title);
32061 beforeResize : function(){
32062 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32066 onResize : function(){
32067 this.refreshSize();
32068 this.syncBodyHeight();
32069 this.adjustAssets();
32071 this.fireEvent("resize", this, this.size.width, this.size.height);
32075 onKeyDown : function(e){
32076 if(this.isVisible()){
32077 this.fireEvent("keydown", this, e);
32082 * Resizes the dialog.
32083 * @param {Number} width
32084 * @param {Number} height
32085 * @return {Roo.BasicDialog} this
32087 resizeTo : function(width, height){
32088 this.el.setSize(width, height);
32089 this.size = {width: width, height: height};
32090 this.syncBodyHeight();
32091 if(this.fixedcenter){
32094 if(this.isVisible()){
32095 this.constrainXY();
32096 this.adjustAssets();
32098 this.fireEvent("resize", this, width, height);
32104 * Resizes the dialog to fit the specified content size.
32105 * @param {Number} width
32106 * @param {Number} height
32107 * @return {Roo.BasicDialog} this
32109 setContentSize : function(w, h){
32110 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32111 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32112 //if(!this.el.isBorderBox()){
32113 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32114 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32117 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32118 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32120 this.resizeTo(w, h);
32125 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32126 * executed in response to a particular key being pressed while the dialog is active.
32127 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32128 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32129 * @param {Function} fn The function to call
32130 * @param {Object} scope (optional) The scope of the function
32131 * @return {Roo.BasicDialog} this
32133 addKeyListener : function(key, fn, scope){
32134 var keyCode, shift, ctrl, alt;
32135 if(typeof key == "object" && !(key instanceof Array)){
32136 keyCode = key["key"];
32137 shift = key["shift"];
32138 ctrl = key["ctrl"];
32143 var handler = function(dlg, e){
32144 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32145 var k = e.getKey();
32146 if(keyCode instanceof Array){
32147 for(var i = 0, len = keyCode.length; i < len; i++){
32148 if(keyCode[i] == k){
32149 fn.call(scope || window, dlg, k, e);
32155 fn.call(scope || window, dlg, k, e);
32160 this.on("keydown", handler);
32165 * Returns the TabPanel component (creates it if it doesn't exist).
32166 * Note: If you wish to simply check for the existence of tabs without creating them,
32167 * check for a null 'tabs' property.
32168 * @return {Roo.TabPanel} The tabs component
32170 getTabs : function(){
32172 this.el.addClass("x-dlg-auto-tabs");
32173 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32174 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32180 * Adds a button to the footer section of the dialog.
32181 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32182 * object or a valid Roo.DomHelper element config
32183 * @param {Function} handler The function called when the button is clicked
32184 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32185 * @return {Roo.Button} The new button
32187 addButton : function(config, handler, scope){
32188 var dh = Roo.DomHelper;
32190 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32192 if(!this.btnContainer){
32193 var tb = this.footer.createChild({
32195 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32196 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32198 this.btnContainer = tb.firstChild.firstChild.firstChild;
32203 minWidth: this.minButtonWidth,
32206 if(typeof config == "string"){
32207 bconfig.text = config;
32210 bconfig.dhconfig = config;
32212 Roo.apply(bconfig, config);
32216 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32217 bconfig.position = Math.max(0, bconfig.position);
32218 fc = this.btnContainer.childNodes[bconfig.position];
32221 var btn = new Roo.Button(
32223 this.btnContainer.insertBefore(document.createElement("td"),fc)
32224 : this.btnContainer.appendChild(document.createElement("td")),
32225 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32228 this.syncBodyHeight();
32231 * Array of all the buttons that have been added to this dialog via addButton
32236 this.buttons.push(btn);
32241 * Sets the default button to be focused when the dialog is displayed.
32242 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32243 * @return {Roo.BasicDialog} this
32245 setDefaultButton : function(btn){
32246 this.defaultButton = btn;
32251 getHeaderFooterHeight : function(safe){
32254 height += this.header.getHeight();
32257 var fm = this.footer.getMargins();
32258 height += (this.footer.getHeight()+fm.top+fm.bottom);
32260 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32261 height += this.centerBg.getPadding("tb");
32266 syncBodyHeight : function()
32268 var bd = this.body, // the text
32269 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32271 var height = this.size.height - this.getHeaderFooterHeight(false);
32272 bd.setHeight(height-bd.getMargins("tb"));
32273 var hh = this.header.getHeight();
32274 var h = this.size.height-hh;
32277 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32278 bw.setHeight(h-cb.getPadding("tb"));
32280 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32281 bd.setWidth(bw.getWidth(true));
32283 this.tabs.syncHeight();
32285 this.tabs.el.repaint();
32291 * Restores the previous state of the dialog if Roo.state is configured.
32292 * @return {Roo.BasicDialog} this
32294 restoreState : function(){
32295 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32296 if(box && box.width){
32297 this.xy = [box.x, box.y];
32298 this.resizeTo(box.width, box.height);
32304 beforeShow : function(){
32306 if(this.fixedcenter){
32307 this.xy = this.el.getCenterXY(true);
32310 Roo.get(document.body).addClass("x-body-masked");
32311 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32314 this.constrainXY();
32318 animShow : function(){
32319 var b = Roo.get(this.animateTarget).getBox();
32320 this.proxy.setSize(b.width, b.height);
32321 this.proxy.setLocation(b.x, b.y);
32323 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32324 true, .35, this.showEl.createDelegate(this));
32328 * Shows the dialog.
32329 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32330 * @return {Roo.BasicDialog} this
32332 show : function(animateTarget){
32333 if (this.fireEvent("beforeshow", this) === false){
32336 if(this.syncHeightBeforeShow){
32337 this.syncBodyHeight();
32338 }else if(this.firstShow){
32339 this.firstShow = false;
32340 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32342 this.animateTarget = animateTarget || this.animateTarget;
32343 if(!this.el.isVisible()){
32345 if(this.animateTarget && Roo.get(this.animateTarget)){
32355 showEl : function(){
32357 this.el.setXY(this.xy);
32359 this.adjustAssets(true);
32362 // IE peekaboo bug - fix found by Dave Fenwick
32366 this.fireEvent("show", this);
32370 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32371 * dialog itself will receive focus.
32373 focus : function(){
32374 if(this.defaultButton){
32375 this.defaultButton.focus();
32377 this.focusEl.focus();
32382 constrainXY : function(){
32383 if(this.constraintoviewport !== false){
32384 if(!this.viewSize){
32385 if(this.container){
32386 var s = this.container.getSize();
32387 this.viewSize = [s.width, s.height];
32389 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32392 var s = Roo.get(this.container||document).getScroll();
32394 var x = this.xy[0], y = this.xy[1];
32395 var w = this.size.width, h = this.size.height;
32396 var vw = this.viewSize[0], vh = this.viewSize[1];
32397 // only move it if it needs it
32399 // first validate right/bottom
32400 if(x + w > vw+s.left){
32404 if(y + h > vh+s.top){
32408 // then make sure top/left isn't negative
32420 if(this.isVisible()){
32421 this.el.setLocation(x, y);
32422 this.adjustAssets();
32429 onDrag : function(){
32430 if(!this.proxyDrag){
32431 this.xy = this.el.getXY();
32432 this.adjustAssets();
32437 adjustAssets : function(doShow){
32438 var x = this.xy[0], y = this.xy[1];
32439 var w = this.size.width, h = this.size.height;
32440 if(doShow === true){
32442 this.shadow.show(this.el);
32448 if(this.shadow && this.shadow.isVisible()){
32449 this.shadow.show(this.el);
32451 if(this.shim && this.shim.isVisible()){
32452 this.shim.setBounds(x, y, w, h);
32457 adjustViewport : function(w, h){
32459 w = Roo.lib.Dom.getViewWidth();
32460 h = Roo.lib.Dom.getViewHeight();
32463 this.viewSize = [w, h];
32464 if(this.modal && this.mask.isVisible()){
32465 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32466 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32468 if(this.isVisible()){
32469 this.constrainXY();
32474 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32475 * shadow, proxy, mask, etc.) Also removes all event listeners.
32476 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32478 destroy : function(removeEl){
32479 if(this.isVisible()){
32480 this.animateTarget = null;
32483 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32485 this.tabs.destroy(removeEl);
32498 for(var i = 0, len = this.buttons.length; i < len; i++){
32499 this.buttons[i].destroy();
32502 this.el.removeAllListeners();
32503 if(removeEl === true){
32504 this.el.update("");
32507 Roo.DialogManager.unregister(this);
32511 startMove : function(){
32512 if(this.proxyDrag){
32515 if(this.constraintoviewport !== false){
32516 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32521 endMove : function(){
32522 if(!this.proxyDrag){
32523 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32525 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32528 this.refreshSize();
32529 this.adjustAssets();
32531 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32535 * Brings this dialog to the front of any other visible dialogs
32536 * @return {Roo.BasicDialog} this
32538 toFront : function(){
32539 Roo.DialogManager.bringToFront(this);
32544 * Sends this dialog to the back (under) of any other visible dialogs
32545 * @return {Roo.BasicDialog} this
32547 toBack : function(){
32548 Roo.DialogManager.sendToBack(this);
32553 * Centers this dialog in the viewport
32554 * @return {Roo.BasicDialog} this
32556 center : function(){
32557 var xy = this.el.getCenterXY(true);
32558 this.moveTo(xy[0], xy[1]);
32563 * Moves the dialog's top-left corner to the specified point
32564 * @param {Number} x
32565 * @param {Number} y
32566 * @return {Roo.BasicDialog} this
32568 moveTo : function(x, y){
32570 if(this.isVisible()){
32571 this.el.setXY(this.xy);
32572 this.adjustAssets();
32578 * Aligns the dialog to the specified element
32579 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32580 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32581 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32582 * @return {Roo.BasicDialog} this
32584 alignTo : function(element, position, offsets){
32585 this.xy = this.el.getAlignToXY(element, position, offsets);
32586 if(this.isVisible()){
32587 this.el.setXY(this.xy);
32588 this.adjustAssets();
32594 * Anchors an element to another element and realigns it when the window is resized.
32595 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32596 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32597 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32598 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32599 * is a number, it is used as the buffer delay (defaults to 50ms).
32600 * @return {Roo.BasicDialog} this
32602 anchorTo : function(el, alignment, offsets, monitorScroll){
32603 var action = function(){
32604 this.alignTo(el, alignment, offsets);
32606 Roo.EventManager.onWindowResize(action, this);
32607 var tm = typeof monitorScroll;
32608 if(tm != 'undefined'){
32609 Roo.EventManager.on(window, 'scroll', action, this,
32610 {buffer: tm == 'number' ? monitorScroll : 50});
32617 * Returns true if the dialog is visible
32618 * @return {Boolean}
32620 isVisible : function(){
32621 return this.el.isVisible();
32625 animHide : function(callback){
32626 var b = Roo.get(this.animateTarget).getBox();
32628 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32630 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32631 this.hideEl.createDelegate(this, [callback]));
32635 * Hides the dialog.
32636 * @param {Function} callback (optional) Function to call when the dialog is hidden
32637 * @return {Roo.BasicDialog} this
32639 hide : function(callback){
32640 if (this.fireEvent("beforehide", this) === false){
32644 this.shadow.hide();
32649 // sometimes animateTarget seems to get set.. causing problems...
32650 // this just double checks..
32651 if(this.animateTarget && Roo.get(this.animateTarget)) {
32652 this.animHide(callback);
32655 this.hideEl(callback);
32661 hideEl : function(callback){
32665 Roo.get(document.body).removeClass("x-body-masked");
32667 this.fireEvent("hide", this);
32668 if(typeof callback == "function"){
32674 hideAction : function(){
32675 this.setLeft("-10000px");
32676 this.setTop("-10000px");
32677 this.setStyle("visibility", "hidden");
32681 refreshSize : function(){
32682 this.size = this.el.getSize();
32683 this.xy = this.el.getXY();
32684 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32688 // z-index is managed by the DialogManager and may be overwritten at any time
32689 setZIndex : function(index){
32691 this.mask.setStyle("z-index", index);
32694 this.shim.setStyle("z-index", ++index);
32697 this.shadow.setZIndex(++index);
32699 this.el.setStyle("z-index", ++index);
32701 this.proxy.setStyle("z-index", ++index);
32704 this.resizer.proxy.setStyle("z-index", ++index);
32707 this.lastZIndex = index;
32711 * Returns the element for this dialog
32712 * @return {Roo.Element} The underlying dialog Element
32714 getEl : function(){
32720 * @class Roo.DialogManager
32721 * Provides global access to BasicDialogs that have been created and
32722 * support for z-indexing (layering) multiple open dialogs.
32724 Roo.DialogManager = function(){
32726 var accessList = [];
32730 var sortDialogs = function(d1, d2){
32731 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32735 var orderDialogs = function(){
32736 accessList.sort(sortDialogs);
32737 var seed = Roo.DialogManager.zseed;
32738 for(var i = 0, len = accessList.length; i < len; i++){
32739 var dlg = accessList[i];
32741 dlg.setZIndex(seed + (i*10));
32748 * The starting z-index for BasicDialogs (defaults to 9000)
32749 * @type Number The z-index value
32754 register : function(dlg){
32755 list[dlg.id] = dlg;
32756 accessList.push(dlg);
32760 unregister : function(dlg){
32761 delete list[dlg.id];
32764 if(!accessList.indexOf){
32765 for( i = 0, len = accessList.length; i < len; i++){
32766 if(accessList[i] == dlg){
32767 accessList.splice(i, 1);
32772 i = accessList.indexOf(dlg);
32774 accessList.splice(i, 1);
32780 * Gets a registered dialog by id
32781 * @param {String/Object} id The id of the dialog or a dialog
32782 * @return {Roo.BasicDialog} this
32784 get : function(id){
32785 return typeof id == "object" ? id : list[id];
32789 * Brings the specified dialog to the front
32790 * @param {String/Object} dlg The id of the dialog or a dialog
32791 * @return {Roo.BasicDialog} this
32793 bringToFront : function(dlg){
32794 dlg = this.get(dlg);
32797 dlg._lastAccess = new Date().getTime();
32804 * Sends the specified dialog to the back
32805 * @param {String/Object} dlg The id of the dialog or a dialog
32806 * @return {Roo.BasicDialog} this
32808 sendToBack : function(dlg){
32809 dlg = this.get(dlg);
32810 dlg._lastAccess = -(new Date().getTime());
32816 * Hides all dialogs
32818 hideAll : function(){
32819 for(var id in list){
32820 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32829 * @class Roo.LayoutDialog
32830 * @extends Roo.BasicDialog
32831 * Dialog which provides adjustments for working with a layout in a Dialog.
32832 * Add your necessary layout config options to the dialog's config.<br>
32833 * Example usage (including a nested layout):
32836 dialog = new Roo.LayoutDialog("download-dlg", {
32845 // layout config merges with the dialog config
32847 tabPosition: "top",
32848 alwaysShowTabs: true
32851 dialog.addKeyListener(27, dialog.hide, dialog);
32852 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32853 dialog.addButton("Build It!", this.getDownload, this);
32855 // we can even add nested layouts
32856 var innerLayout = new Roo.BorderLayout("dl-inner", {
32866 innerLayout.beginUpdate();
32867 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32868 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32869 innerLayout.endUpdate(true);
32871 var layout = dialog.getLayout();
32872 layout.beginUpdate();
32873 layout.add("center", new Roo.ContentPanel("standard-panel",
32874 {title: "Download the Source", fitToFrame:true}));
32875 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32876 {title: "Build your own roo.js"}));
32877 layout.getRegion("center").showPanel(sp);
32878 layout.endUpdate();
32882 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32883 * @param {Object} config configuration options
32885 Roo.LayoutDialog = function(el, cfg){
32888 if (typeof(cfg) == 'undefined') {
32889 config = Roo.apply({}, el);
32890 // not sure why we use documentElement here.. - it should always be body.
32891 // IE7 borks horribly if we use documentElement.
32892 // webkit also does not like documentElement - it creates a body element...
32893 el = Roo.get( document.body || document.documentElement ).createChild();
32894 //config.autoCreate = true;
32898 config.autoTabs = false;
32899 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32900 this.body.setStyle({overflow:"hidden", position:"relative"});
32901 this.layout = new Roo.BorderLayout(this.body.dom, config);
32902 this.layout.monitorWindowResize = false;
32903 this.el.addClass("x-dlg-auto-layout");
32904 // fix case when center region overwrites center function
32905 this.center = Roo.BasicDialog.prototype.center;
32906 this.on("show", this.layout.layout, this.layout, true);
32907 if (config.items) {
32908 var xitems = config.items;
32909 delete config.items;
32910 Roo.each(xitems, this.addxtype, this);
32915 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32917 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32920 endUpdate : function(){
32921 this.layout.endUpdate();
32925 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32928 beginUpdate : function(){
32929 this.layout.beginUpdate();
32933 * Get the BorderLayout for this dialog
32934 * @return {Roo.BorderLayout}
32936 getLayout : function(){
32937 return this.layout;
32940 showEl : function(){
32941 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32943 this.layout.layout();
32948 // Use the syncHeightBeforeShow config option to control this automatically
32949 syncBodyHeight : function(){
32950 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32951 if(this.layout){this.layout.layout();}
32955 * Add an xtype element (actually adds to the layout.)
32956 * @return {Object} xdata xtype object data.
32959 addxtype : function(c) {
32960 return this.layout.addxtype(c);
32964 * Ext JS Library 1.1.1
32965 * Copyright(c) 2006-2007, Ext JS, LLC.
32967 * Originally Released Under LGPL - original licence link has changed is not relivant.
32970 * <script type="text/javascript">
32974 * @class Roo.MessageBox
32975 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32979 Roo.Msg.alert('Status', 'Changes saved successfully.');
32981 // Prompt for user data:
32982 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32984 // process text value...
32988 // Show a dialog using config options:
32990 title:'Save Changes?',
32991 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32992 buttons: Roo.Msg.YESNOCANCEL,
32999 Roo.MessageBox = function(){
33000 var dlg, opt, mask, waitTimer;
33001 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33002 var buttons, activeTextEl, bwidth;
33005 var handleButton = function(button){
33007 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33011 var handleHide = function(){
33012 if(opt && opt.cls){
33013 dlg.el.removeClass(opt.cls);
33016 Roo.TaskMgr.stop(waitTimer);
33022 var updateButtons = function(b){
33025 buttons["ok"].hide();
33026 buttons["cancel"].hide();
33027 buttons["yes"].hide();
33028 buttons["no"].hide();
33029 dlg.footer.dom.style.display = 'none';
33032 dlg.footer.dom.style.display = '';
33033 for(var k in buttons){
33034 if(typeof buttons[k] != "function"){
33037 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33038 width += buttons[k].el.getWidth()+15;
33048 var handleEsc = function(d, k, e){
33049 if(opt && opt.closable !== false){
33059 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33060 * @return {Roo.BasicDialog} The BasicDialog element
33062 getDialog : function(){
33064 dlg = new Roo.BasicDialog("x-msg-box", {
33069 constraintoviewport:false,
33071 collapsible : false,
33074 width:400, height:100,
33075 buttonAlign:"center",
33076 closeClick : function(){
33077 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33078 handleButton("no");
33080 handleButton("cancel");
33084 dlg.on("hide", handleHide);
33086 dlg.addKeyListener(27, handleEsc);
33088 var bt = this.buttonText;
33089 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33090 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33091 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33092 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33093 bodyEl = dlg.body.createChild({
33095 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>'
33097 msgEl = bodyEl.dom.firstChild;
33098 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33099 textboxEl.enableDisplayMode();
33100 textboxEl.addKeyListener([10,13], function(){
33101 if(dlg.isVisible() && opt && opt.buttons){
33102 if(opt.buttons.ok){
33103 handleButton("ok");
33104 }else if(opt.buttons.yes){
33105 handleButton("yes");
33109 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33110 textareaEl.enableDisplayMode();
33111 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33112 progressEl.enableDisplayMode();
33113 var pf = progressEl.dom.firstChild;
33115 pp = Roo.get(pf.firstChild);
33116 pp.setHeight(pf.offsetHeight);
33124 * Updates the message box body text
33125 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33126 * the XHTML-compliant non-breaking space character '&#160;')
33127 * @return {Roo.MessageBox} This message box
33129 updateText : function(text){
33130 if(!dlg.isVisible() && !opt.width){
33131 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33133 msgEl.innerHTML = text || ' ';
33135 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33136 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33138 Math.min(opt.width || cw , this.maxWidth),
33139 Math.max(opt.minWidth || this.minWidth, bwidth)
33142 activeTextEl.setWidth(w);
33144 if(dlg.isVisible()){
33145 dlg.fixedcenter = false;
33147 // to big, make it scroll. = But as usual stupid IE does not support
33150 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33151 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33152 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33154 bodyEl.dom.style.height = '';
33155 bodyEl.dom.style.overflowY = '';
33158 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33160 bodyEl.dom.style.overflowX = '';
33163 dlg.setContentSize(w, bodyEl.getHeight());
33164 if(dlg.isVisible()){
33165 dlg.fixedcenter = true;
33171 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33172 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33173 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33174 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33175 * @return {Roo.MessageBox} This message box
33177 updateProgress : function(value, text){
33179 this.updateText(text);
33181 if (pp) { // weird bug on my firefox - for some reason this is not defined
33182 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33188 * Returns true if the message box is currently displayed
33189 * @return {Boolean} True if the message box is visible, else false
33191 isVisible : function(){
33192 return dlg && dlg.isVisible();
33196 * Hides the message box if it is displayed
33199 if(this.isVisible()){
33205 * Displays a new message box, or reinitializes an existing message box, based on the config options
33206 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33207 * The following config object properties are supported:
33209 Property Type Description
33210 ---------- --------------- ------------------------------------------------------------------------------------
33211 animEl String/Element An id or Element from which the message box should animate as it opens and
33212 closes (defaults to undefined)
33213 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33214 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33215 closable Boolean False to hide the top-right close button (defaults to true). Note that
33216 progress and wait dialogs will ignore this property and always hide the
33217 close button as they can only be closed programmatically.
33218 cls String A custom CSS class to apply to the message box element
33219 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33220 displayed (defaults to 75)
33221 fn Function A callback function to execute after closing the dialog. The arguments to the
33222 function will be btn (the name of the button that was clicked, if applicable,
33223 e.g. "ok"), and text (the value of the active text field, if applicable).
33224 Progress and wait dialogs will ignore this option since they do not respond to
33225 user actions and can only be closed programmatically, so any required function
33226 should be called by the same code after it closes the dialog.
33227 icon String A CSS class that provides a background image to be used as an icon for
33228 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33229 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33230 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33231 modal Boolean False to allow user interaction with the page while the message box is
33232 displayed (defaults to true)
33233 msg String A string that will replace the existing message box body text (defaults
33234 to the XHTML-compliant non-breaking space character ' ')
33235 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33236 progress Boolean True to display a progress bar (defaults to false)
33237 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33238 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33239 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33240 title String The title text
33241 value String The string value to set into the active textbox element if displayed
33242 wait Boolean True to display a progress bar (defaults to false)
33243 width Number The width of the dialog in pixels
33250 msg: 'Please enter your address:',
33252 buttons: Roo.MessageBox.OKCANCEL,
33255 animEl: 'addAddressBtn'
33258 * @param {Object} config Configuration options
33259 * @return {Roo.MessageBox} This message box
33261 show : function(options)
33264 // this causes nightmares if you show one dialog after another
33265 // especially on callbacks..
33267 if(this.isVisible()){
33270 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33271 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33272 Roo.log("New Dialog Message:" + options.msg )
33273 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33274 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33277 var d = this.getDialog();
33279 d.setTitle(opt.title || " ");
33280 d.close.setDisplayed(opt.closable !== false);
33281 activeTextEl = textboxEl;
33282 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33287 textareaEl.setHeight(typeof opt.multiline == "number" ?
33288 opt.multiline : this.defaultTextHeight);
33289 activeTextEl = textareaEl;
33298 progressEl.setDisplayed(opt.progress === true);
33299 this.updateProgress(0);
33300 activeTextEl.dom.value = opt.value || "";
33302 dlg.setDefaultButton(activeTextEl);
33304 var bs = opt.buttons;
33307 db = buttons["ok"];
33308 }else if(bs && bs.yes){
33309 db = buttons["yes"];
33311 dlg.setDefaultButton(db);
33313 bwidth = updateButtons(opt.buttons);
33314 this.updateText(opt.msg);
33316 d.el.addClass(opt.cls);
33318 d.proxyDrag = opt.proxyDrag === true;
33319 d.modal = opt.modal !== false;
33320 d.mask = opt.modal !== false ? mask : false;
33321 if(!d.isVisible()){
33322 // force it to the end of the z-index stack so it gets a cursor in FF
33323 document.body.appendChild(dlg.el.dom);
33324 d.animateTarget = null;
33325 d.show(options.animEl);
33331 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33332 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33333 * and closing the message box when the process is complete.
33334 * @param {String} title The title bar text
33335 * @param {String} msg The message box body text
33336 * @return {Roo.MessageBox} This message box
33338 progress : function(title, msg){
33345 minWidth: this.minProgressWidth,
33352 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33353 * If a callback function is passed it will be called after the user clicks the button, and the
33354 * id of the button that was clicked will be passed as the only parameter to the callback
33355 * (could also be the top-right close button).
33356 * @param {String} title The title bar text
33357 * @param {String} msg The message box body text
33358 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33359 * @param {Object} scope (optional) The scope of the callback function
33360 * @return {Roo.MessageBox} This message box
33362 alert : function(title, msg, fn, scope){
33375 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33376 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33377 * You are responsible for closing the message box when the process is complete.
33378 * @param {String} msg The message box body text
33379 * @param {String} title (optional) The title bar text
33380 * @return {Roo.MessageBox} This message box
33382 wait : function(msg, title){
33393 waitTimer = Roo.TaskMgr.start({
33395 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33403 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33404 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33405 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33406 * @param {String} title The title bar text
33407 * @param {String} msg The message box body text
33408 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33409 * @param {Object} scope (optional) The scope of the callback function
33410 * @return {Roo.MessageBox} This message box
33412 confirm : function(title, msg, fn, scope){
33416 buttons: this.YESNO,
33425 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33426 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33427 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33428 * (could also be the top-right close button) and the text that was entered will be passed as the two
33429 * parameters to the callback.
33430 * @param {String} title The title bar text
33431 * @param {String} msg The message box body text
33432 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33433 * @param {Object} scope (optional) The scope of the callback function
33434 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33435 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33436 * @return {Roo.MessageBox} This message box
33438 prompt : function(title, msg, fn, scope, multiline){
33442 buttons: this.OKCANCEL,
33447 multiline: multiline,
33454 * Button config that displays a single OK button
33459 * Button config that displays Yes and No buttons
33462 YESNO : {yes:true, no:true},
33464 * Button config that displays OK and Cancel buttons
33467 OKCANCEL : {ok:true, cancel:true},
33469 * Button config that displays Yes, No and Cancel buttons
33472 YESNOCANCEL : {yes:true, no:true, cancel:true},
33475 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33478 defaultTextHeight : 75,
33480 * The maximum width in pixels of the message box (defaults to 600)
33485 * The minimum width in pixels of the message box (defaults to 100)
33490 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33491 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33494 minProgressWidth : 250,
33496 * An object containing the default button text strings that can be overriden for localized language support.
33497 * Supported properties are: ok, cancel, yes and no.
33498 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33511 * Shorthand for {@link Roo.MessageBox}
33513 Roo.Msg = Roo.MessageBox;/*
33515 * Ext JS Library 1.1.1
33516 * Copyright(c) 2006-2007, Ext JS, LLC.
33518 * Originally Released Under LGPL - original licence link has changed is not relivant.
33521 * <script type="text/javascript">
33524 * @class Roo.QuickTips
33525 * Provides attractive and customizable tooltips for any element.
33528 Roo.QuickTips = function(){
33529 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33530 var ce, bd, xy, dd;
33531 var visible = false, disabled = true, inited = false;
33532 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33534 var onOver = function(e){
33538 var t = e.getTarget();
33539 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33542 if(ce && t == ce.el){
33543 clearTimeout(hideProc);
33546 if(t && tagEls[t.id]){
33547 tagEls[t.id].el = t;
33548 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33551 var ttp, et = Roo.fly(t);
33552 var ns = cfg.namespace;
33553 if(tm.interceptTitles && t.title){
33556 t.removeAttribute("title");
33557 e.preventDefault();
33559 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33562 showProc = show.defer(tm.showDelay, tm, [{
33565 width: et.getAttributeNS(ns, cfg.width),
33566 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33567 title: et.getAttributeNS(ns, cfg.title),
33568 cls: et.getAttributeNS(ns, cfg.cls)
33573 var onOut = function(e){
33574 clearTimeout(showProc);
33575 var t = e.getTarget();
33576 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33577 hideProc = setTimeout(hide, tm.hideDelay);
33581 var onMove = function(e){
33587 if(tm.trackMouse && ce){
33592 var onDown = function(e){
33593 clearTimeout(showProc);
33594 clearTimeout(hideProc);
33596 if(tm.hideOnClick){
33599 tm.enable.defer(100, tm);
33604 var getPad = function(){
33605 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33608 var show = function(o){
33612 clearTimeout(dismissProc);
33614 if(removeCls){ // in case manually hidden
33615 el.removeClass(removeCls);
33619 el.addClass(ce.cls);
33620 removeCls = ce.cls;
33623 tipTitle.update(ce.title);
33626 tipTitle.update('');
33629 el.dom.style.width = tm.maxWidth+'px';
33630 //tipBody.dom.style.width = '';
33631 tipBodyText.update(o.text);
33632 var p = getPad(), w = ce.width;
33634 var td = tipBodyText.dom;
33635 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33636 if(aw > tm.maxWidth){
33638 }else if(aw < tm.minWidth){
33644 //tipBody.setWidth(w);
33645 el.setWidth(parseInt(w, 10) + p);
33646 if(ce.autoHide === false){
33647 close.setDisplayed(true);
33652 close.setDisplayed(false);
33658 el.avoidY = xy[1]-18;
33663 el.setStyle("visibility", "visible");
33664 el.fadeIn({callback: afterShow});
33670 var afterShow = function(){
33674 if(tm.autoDismiss && ce.autoHide !== false){
33675 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33680 var hide = function(noanim){
33681 clearTimeout(dismissProc);
33682 clearTimeout(hideProc);
33684 if(el.isVisible()){
33686 if(noanim !== true && tm.animate){
33687 el.fadeOut({callback: afterHide});
33694 var afterHide = function(){
33697 el.removeClass(removeCls);
33704 * @cfg {Number} minWidth
33705 * The minimum width of the quick tip (defaults to 40)
33709 * @cfg {Number} maxWidth
33710 * The maximum width of the quick tip (defaults to 300)
33714 * @cfg {Boolean} interceptTitles
33715 * True to automatically use the element's DOM title value if available (defaults to false)
33717 interceptTitles : false,
33719 * @cfg {Boolean} trackMouse
33720 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33722 trackMouse : false,
33724 * @cfg {Boolean} hideOnClick
33725 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33727 hideOnClick : true,
33729 * @cfg {Number} showDelay
33730 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33734 * @cfg {Number} hideDelay
33735 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33739 * @cfg {Boolean} autoHide
33740 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33741 * Used in conjunction with hideDelay.
33746 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33747 * (defaults to true). Used in conjunction with autoDismissDelay.
33749 autoDismiss : true,
33752 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33754 autoDismissDelay : 5000,
33756 * @cfg {Boolean} animate
33757 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33762 * @cfg {String} title
33763 * Title text to display (defaults to ''). This can be any valid HTML markup.
33767 * @cfg {String} text
33768 * Body text to display (defaults to ''). This can be any valid HTML markup.
33772 * @cfg {String} cls
33773 * A CSS class to apply to the base quick tip element (defaults to '').
33777 * @cfg {Number} width
33778 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33779 * minWidth or maxWidth.
33784 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33785 * or display QuickTips in a page.
33788 tm = Roo.QuickTips;
33789 cfg = tm.tagConfig;
33791 if(!Roo.isReady){ // allow calling of init() before onReady
33792 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33795 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33796 el.fxDefaults = {stopFx: true};
33797 // maximum custom styling
33798 //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>');
33799 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>');
33800 tipTitle = el.child('h3');
33801 tipTitle.enableDisplayMode("block");
33802 tipBody = el.child('div.x-tip-bd');
33803 tipBodyText = el.child('div.x-tip-bd-inner');
33804 //bdLeft = el.child('div.x-tip-bd-left');
33805 //bdRight = el.child('div.x-tip-bd-right');
33806 close = el.child('div.x-tip-close');
33807 close.enableDisplayMode("block");
33808 close.on("click", hide);
33809 var d = Roo.get(document);
33810 d.on("mousedown", onDown);
33811 d.on("mouseover", onOver);
33812 d.on("mouseout", onOut);
33813 d.on("mousemove", onMove);
33814 esc = d.addKeyListener(27, hide);
33817 dd = el.initDD("default", null, {
33818 onDrag : function(){
33822 dd.setHandleElId(tipTitle.id);
33831 * Configures a new quick tip instance and assigns it to a target element. The following config options
33834 Property Type Description
33835 ---------- --------------------- ------------------------------------------------------------------------
33836 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33838 * @param {Object} config The config object
33840 register : function(config){
33841 var cs = config instanceof Array ? config : arguments;
33842 for(var i = 0, len = cs.length; i < len; i++) {
33844 var target = c.target;
33846 if(target instanceof Array){
33847 for(var j = 0, jlen = target.length; j < jlen; j++){
33848 tagEls[target[j]] = c;
33851 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33858 * Removes this quick tip from its element and destroys it.
33859 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33861 unregister : function(el){
33862 delete tagEls[Roo.id(el)];
33866 * Enable this quick tip.
33868 enable : function(){
33869 if(inited && disabled){
33871 if(locks.length < 1){
33878 * Disable this quick tip.
33880 disable : function(){
33882 clearTimeout(showProc);
33883 clearTimeout(hideProc);
33884 clearTimeout(dismissProc);
33892 * Returns true if the quick tip is enabled, else false.
33894 isEnabled : function(){
33900 namespace : "roo", // was ext?? this may break..
33901 alt_namespace : "ext",
33902 attribute : "qtip",
33912 // backwards compat
33913 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33915 * Ext JS Library 1.1.1
33916 * Copyright(c) 2006-2007, Ext JS, LLC.
33918 * Originally Released Under LGPL - original licence link has changed is not relivant.
33921 * <script type="text/javascript">
33926 * @class Roo.tree.TreePanel
33927 * @extends Roo.data.Tree
33929 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33930 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33931 * @cfg {Boolean} enableDD true to enable drag and drop
33932 * @cfg {Boolean} enableDrag true to enable just drag
33933 * @cfg {Boolean} enableDrop true to enable just drop
33934 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33935 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33936 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33937 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33938 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33939 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33940 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33941 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33942 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33943 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33944 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33945 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33946 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33947 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33948 * @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>
33949 * @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>
33952 * @param {String/HTMLElement/Element} el The container element
33953 * @param {Object} config
33955 Roo.tree.TreePanel = function(el, config){
33957 var loader = false;
33959 root = config.root;
33960 delete config.root;
33962 if (config.loader) {
33963 loader = config.loader;
33964 delete config.loader;
33967 Roo.apply(this, config);
33968 Roo.tree.TreePanel.superclass.constructor.call(this);
33969 this.el = Roo.get(el);
33970 this.el.addClass('x-tree');
33971 //console.log(root);
33973 this.setRootNode( Roo.factory(root, Roo.tree));
33976 this.loader = Roo.factory(loader, Roo.tree);
33979 * Read-only. The id of the container element becomes this TreePanel's id.
33981 this.id = this.el.id;
33984 * @event beforeload
33985 * Fires before a node is loaded, return false to cancel
33986 * @param {Node} node The node being loaded
33988 "beforeload" : true,
33991 * Fires when a node is loaded
33992 * @param {Node} node The node that was loaded
33996 * @event textchange
33997 * Fires when the text for a node is changed
33998 * @param {Node} node The node
33999 * @param {String} text The new text
34000 * @param {String} oldText The old text
34002 "textchange" : true,
34004 * @event beforeexpand
34005 * Fires before a node is expanded, return false to cancel.
34006 * @param {Node} node The node
34007 * @param {Boolean} deep
34008 * @param {Boolean} anim
34010 "beforeexpand" : true,
34012 * @event beforecollapse
34013 * Fires before a node is collapsed, return false to cancel.
34014 * @param {Node} node The node
34015 * @param {Boolean} deep
34016 * @param {Boolean} anim
34018 "beforecollapse" : true,
34021 * Fires when a node is expanded
34022 * @param {Node} node The node
34026 * @event disabledchange
34027 * Fires when the disabled status of a node changes
34028 * @param {Node} node The node
34029 * @param {Boolean} disabled
34031 "disabledchange" : true,
34034 * Fires when a node is collapsed
34035 * @param {Node} node The node
34039 * @event beforeclick
34040 * Fires before click processing on a node. Return false to cancel the default action.
34041 * @param {Node} node The node
34042 * @param {Roo.EventObject} e The event object
34044 "beforeclick":true,
34046 * @event checkchange
34047 * Fires when a node with a checkbox's checked property changes
34048 * @param {Node} this This node
34049 * @param {Boolean} checked
34051 "checkchange":true,
34054 * Fires when a node is clicked
34055 * @param {Node} node The node
34056 * @param {Roo.EventObject} e The event object
34061 * Fires when a node is double clicked
34062 * @param {Node} node The node
34063 * @param {Roo.EventObject} e The event object
34067 * @event contextmenu
34068 * Fires when a node is right clicked
34069 * @param {Node} node The node
34070 * @param {Roo.EventObject} e The event object
34072 "contextmenu":true,
34074 * @event beforechildrenrendered
34075 * Fires right before the child nodes for a node are rendered
34076 * @param {Node} node The node
34078 "beforechildrenrendered":true,
34081 * Fires when a node starts being dragged
34082 * @param {Roo.tree.TreePanel} this
34083 * @param {Roo.tree.TreeNode} node
34084 * @param {event} e The raw browser event
34086 "startdrag" : true,
34089 * Fires when a drag operation is complete
34090 * @param {Roo.tree.TreePanel} this
34091 * @param {Roo.tree.TreeNode} node
34092 * @param {event} e The raw browser event
34097 * Fires when a dragged node is dropped on a valid DD target
34098 * @param {Roo.tree.TreePanel} this
34099 * @param {Roo.tree.TreeNode} node
34100 * @param {DD} dd The dd it was dropped on
34101 * @param {event} e The raw browser event
34105 * @event beforenodedrop
34106 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34107 * passed to handlers has the following properties:<br />
34108 * <ul style="padding:5px;padding-left:16px;">
34109 * <li>tree - The TreePanel</li>
34110 * <li>target - The node being targeted for the drop</li>
34111 * <li>data - The drag data from the drag source</li>
34112 * <li>point - The point of the drop - append, above or below</li>
34113 * <li>source - The drag source</li>
34114 * <li>rawEvent - Raw mouse event</li>
34115 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34116 * to be inserted by setting them on this object.</li>
34117 * <li>cancel - Set this to true to cancel the drop.</li>
34119 * @param {Object} dropEvent
34121 "beforenodedrop" : true,
34124 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34125 * passed to handlers has the following properties:<br />
34126 * <ul style="padding:5px;padding-left:16px;">
34127 * <li>tree - The TreePanel</li>
34128 * <li>target - The node being targeted for the drop</li>
34129 * <li>data - The drag data from the drag source</li>
34130 * <li>point - The point of the drop - append, above or below</li>
34131 * <li>source - The drag source</li>
34132 * <li>rawEvent - Raw mouse event</li>
34133 * <li>dropNode - Dropped node(s).</li>
34135 * @param {Object} dropEvent
34139 * @event nodedragover
34140 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34141 * passed to handlers has the following properties:<br />
34142 * <ul style="padding:5px;padding-left:16px;">
34143 * <li>tree - The TreePanel</li>
34144 * <li>target - The node being targeted for the drop</li>
34145 * <li>data - The drag data from the drag source</li>
34146 * <li>point - The point of the drop - append, above or below</li>
34147 * <li>source - The drag source</li>
34148 * <li>rawEvent - Raw mouse event</li>
34149 * <li>dropNode - Drop node(s) provided by the source.</li>
34150 * <li>cancel - Set this to true to signal drop not allowed.</li>
34152 * @param {Object} dragOverEvent
34154 "nodedragover" : true
34157 if(this.singleExpand){
34158 this.on("beforeexpand", this.restrictExpand, this);
34161 this.editor.tree = this;
34162 this.editor = Roo.factory(this.editor, Roo.tree);
34165 if (this.selModel) {
34166 this.selModel = Roo.factory(this.selModel, Roo.tree);
34170 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34171 rootVisible : true,
34172 animate: Roo.enableFx,
34175 hlDrop : Roo.enableFx,
34179 rendererTip: false,
34181 restrictExpand : function(node){
34182 var p = node.parentNode;
34184 if(p.expandedChild && p.expandedChild.parentNode == p){
34185 p.expandedChild.collapse();
34187 p.expandedChild = node;
34191 // private override
34192 setRootNode : function(node){
34193 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34194 if(!this.rootVisible){
34195 node.ui = new Roo.tree.RootTreeNodeUI(node);
34201 * Returns the container element for this TreePanel
34203 getEl : function(){
34208 * Returns the default TreeLoader for this TreePanel
34210 getLoader : function(){
34211 return this.loader;
34217 expandAll : function(){
34218 this.root.expand(true);
34222 * Collapse all nodes
34224 collapseAll : function(){
34225 this.root.collapse(true);
34229 * Returns the selection model used by this TreePanel
34231 getSelectionModel : function(){
34232 if(!this.selModel){
34233 this.selModel = new Roo.tree.DefaultSelectionModel();
34235 return this.selModel;
34239 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34240 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34241 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34244 getChecked : function(a, startNode){
34245 startNode = startNode || this.root;
34247 var f = function(){
34248 if(this.attributes.checked){
34249 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34252 startNode.cascade(f);
34257 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34258 * @param {String} path
34259 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34260 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34261 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34263 expandPath : function(path, attr, callback){
34264 attr = attr || "id";
34265 var keys = path.split(this.pathSeparator);
34266 var curNode = this.root;
34267 if(curNode.attributes[attr] != keys[1]){ // invalid root
34269 callback(false, null);
34274 var f = function(){
34275 if(++index == keys.length){
34277 callback(true, curNode);
34281 var c = curNode.findChild(attr, keys[index]);
34284 callback(false, curNode);
34289 c.expand(false, false, f);
34291 curNode.expand(false, false, f);
34295 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34296 * @param {String} path
34297 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34298 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34299 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34301 selectPath : function(path, attr, callback){
34302 attr = attr || "id";
34303 var keys = path.split(this.pathSeparator);
34304 var v = keys.pop();
34305 if(keys.length > 0){
34306 var f = function(success, node){
34307 if(success && node){
34308 var n = node.findChild(attr, v);
34314 }else if(callback){
34315 callback(false, n);
34319 callback(false, n);
34323 this.expandPath(keys.join(this.pathSeparator), attr, f);
34325 this.root.select();
34327 callback(true, this.root);
34332 getTreeEl : function(){
34337 * Trigger rendering of this TreePanel
34339 render : function(){
34340 if (this.innerCt) {
34341 return this; // stop it rendering more than once!!
34344 this.innerCt = this.el.createChild({tag:"ul",
34345 cls:"x-tree-root-ct " +
34346 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34348 if(this.containerScroll){
34349 Roo.dd.ScrollManager.register(this.el);
34351 if((this.enableDD || this.enableDrop) && !this.dropZone){
34353 * The dropZone used by this tree if drop is enabled
34354 * @type Roo.tree.TreeDropZone
34356 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34357 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34360 if((this.enableDD || this.enableDrag) && !this.dragZone){
34362 * The dragZone used by this tree if drag is enabled
34363 * @type Roo.tree.TreeDragZone
34365 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34366 ddGroup: this.ddGroup || "TreeDD",
34367 scroll: this.ddScroll
34370 this.getSelectionModel().init(this);
34372 Roo.log("ROOT not set in tree");
34375 this.root.render();
34376 if(!this.rootVisible){
34377 this.root.renderChildren();
34383 * Ext JS Library 1.1.1
34384 * Copyright(c) 2006-2007, Ext JS, LLC.
34386 * Originally Released Under LGPL - original licence link has changed is not relivant.
34389 * <script type="text/javascript">
34394 * @class Roo.tree.DefaultSelectionModel
34395 * @extends Roo.util.Observable
34396 * The default single selection for a TreePanel.
34397 * @param {Object} cfg Configuration
34399 Roo.tree.DefaultSelectionModel = function(cfg){
34400 this.selNode = null;
34406 * @event selectionchange
34407 * Fires when the selected node changes
34408 * @param {DefaultSelectionModel} this
34409 * @param {TreeNode} node the new selection
34411 "selectionchange" : true,
34414 * @event beforeselect
34415 * Fires before the selected node changes, return false to cancel the change
34416 * @param {DefaultSelectionModel} this
34417 * @param {TreeNode} node the new selection
34418 * @param {TreeNode} node the old selection
34420 "beforeselect" : true
34423 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34426 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34427 init : function(tree){
34429 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34430 tree.on("click", this.onNodeClick, this);
34433 onNodeClick : function(node, e){
34434 if (e.ctrlKey && this.selNode == node) {
34435 this.unselect(node);
34443 * @param {TreeNode} node The node to select
34444 * @return {TreeNode} The selected node
34446 select : function(node){
34447 var last = this.selNode;
34448 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34450 last.ui.onSelectedChange(false);
34452 this.selNode = node;
34453 node.ui.onSelectedChange(true);
34454 this.fireEvent("selectionchange", this, node, last);
34461 * @param {TreeNode} node The node to unselect
34463 unselect : function(node){
34464 if(this.selNode == node){
34465 this.clearSelections();
34470 * Clear all selections
34472 clearSelections : function(){
34473 var n = this.selNode;
34475 n.ui.onSelectedChange(false);
34476 this.selNode = null;
34477 this.fireEvent("selectionchange", this, null);
34483 * Get the selected node
34484 * @return {TreeNode} The selected node
34486 getSelectedNode : function(){
34487 return this.selNode;
34491 * Returns true if the node is selected
34492 * @param {TreeNode} node The node to check
34493 * @return {Boolean}
34495 isSelected : function(node){
34496 return this.selNode == node;
34500 * Selects the node above the selected node in the tree, intelligently walking the nodes
34501 * @return TreeNode The new selection
34503 selectPrevious : function(){
34504 var s = this.selNode || this.lastSelNode;
34508 var ps = s.previousSibling;
34510 if(!ps.isExpanded() || ps.childNodes.length < 1){
34511 return this.select(ps);
34513 var lc = ps.lastChild;
34514 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34517 return this.select(lc);
34519 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34520 return this.select(s.parentNode);
34526 * Selects the node above the selected node in the tree, intelligently walking the nodes
34527 * @return TreeNode The new selection
34529 selectNext : function(){
34530 var s = this.selNode || this.lastSelNode;
34534 if(s.firstChild && s.isExpanded()){
34535 return this.select(s.firstChild);
34536 }else if(s.nextSibling){
34537 return this.select(s.nextSibling);
34538 }else if(s.parentNode){
34540 s.parentNode.bubble(function(){
34541 if(this.nextSibling){
34542 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34551 onKeyDown : function(e){
34552 var s = this.selNode || this.lastSelNode;
34553 // undesirable, but required
34558 var k = e.getKey();
34566 this.selectPrevious();
34569 e.preventDefault();
34570 if(s.hasChildNodes()){
34571 if(!s.isExpanded()){
34573 }else if(s.firstChild){
34574 this.select(s.firstChild, e);
34579 e.preventDefault();
34580 if(s.hasChildNodes() && s.isExpanded()){
34582 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34583 this.select(s.parentNode, e);
34591 * @class Roo.tree.MultiSelectionModel
34592 * @extends Roo.util.Observable
34593 * Multi selection for a TreePanel.
34594 * @param {Object} cfg Configuration
34596 Roo.tree.MultiSelectionModel = function(){
34597 this.selNodes = [];
34601 * @event selectionchange
34602 * Fires when the selected nodes change
34603 * @param {MultiSelectionModel} this
34604 * @param {Array} nodes Array of the selected nodes
34606 "selectionchange" : true
34608 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34612 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34613 init : function(tree){
34615 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34616 tree.on("click", this.onNodeClick, this);
34619 onNodeClick : function(node, e){
34620 this.select(node, e, e.ctrlKey);
34625 * @param {TreeNode} node The node to select
34626 * @param {EventObject} e (optional) An event associated with the selection
34627 * @param {Boolean} keepExisting True to retain existing selections
34628 * @return {TreeNode} The selected node
34630 select : function(node, e, keepExisting){
34631 if(keepExisting !== true){
34632 this.clearSelections(true);
34634 if(this.isSelected(node)){
34635 this.lastSelNode = node;
34638 this.selNodes.push(node);
34639 this.selMap[node.id] = node;
34640 this.lastSelNode = node;
34641 node.ui.onSelectedChange(true);
34642 this.fireEvent("selectionchange", this, this.selNodes);
34648 * @param {TreeNode} node The node to unselect
34650 unselect : function(node){
34651 if(this.selMap[node.id]){
34652 node.ui.onSelectedChange(false);
34653 var sn = this.selNodes;
34656 index = sn.indexOf(node);
34658 for(var i = 0, len = sn.length; i < len; i++){
34666 this.selNodes.splice(index, 1);
34668 delete this.selMap[node.id];
34669 this.fireEvent("selectionchange", this, this.selNodes);
34674 * Clear all selections
34676 clearSelections : function(suppressEvent){
34677 var sn = this.selNodes;
34679 for(var i = 0, len = sn.length; i < len; i++){
34680 sn[i].ui.onSelectedChange(false);
34682 this.selNodes = [];
34684 if(suppressEvent !== true){
34685 this.fireEvent("selectionchange", this, this.selNodes);
34691 * Returns true if the node is selected
34692 * @param {TreeNode} node The node to check
34693 * @return {Boolean}
34695 isSelected : function(node){
34696 return this.selMap[node.id] ? true : false;
34700 * Returns an array of the selected nodes
34703 getSelectedNodes : function(){
34704 return this.selNodes;
34707 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34709 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34711 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34714 * Ext JS Library 1.1.1
34715 * Copyright(c) 2006-2007, Ext JS, LLC.
34717 * Originally Released Under LGPL - original licence link has changed is not relivant.
34720 * <script type="text/javascript">
34724 * @class Roo.tree.TreeNode
34725 * @extends Roo.data.Node
34726 * @cfg {String} text The text for this node
34727 * @cfg {Boolean} expanded true to start the node expanded
34728 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34729 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34730 * @cfg {Boolean} disabled true to start the node disabled
34731 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34732 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34733 * @cfg {String} cls A css class to be added to the node
34734 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34735 * @cfg {String} href URL of the link used for the node (defaults to #)
34736 * @cfg {String} hrefTarget target frame for the link
34737 * @cfg {String} qtip An Ext QuickTip for the node
34738 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34739 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34740 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34741 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34742 * (defaults to undefined with no checkbox rendered)
34744 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34746 Roo.tree.TreeNode = function(attributes){
34747 attributes = attributes || {};
34748 if(typeof attributes == "string"){
34749 attributes = {text: attributes};
34751 this.childrenRendered = false;
34752 this.rendered = false;
34753 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34754 this.expanded = attributes.expanded === true;
34755 this.isTarget = attributes.isTarget !== false;
34756 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34757 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34760 * Read-only. The text for this node. To change it use setText().
34763 this.text = attributes.text;
34765 * True if this node is disabled.
34768 this.disabled = attributes.disabled === true;
34772 * @event textchange
34773 * Fires when the text for this node is changed
34774 * @param {Node} this This node
34775 * @param {String} text The new text
34776 * @param {String} oldText The old text
34778 "textchange" : true,
34780 * @event beforeexpand
34781 * Fires before this node is expanded, return false to cancel.
34782 * @param {Node} this This node
34783 * @param {Boolean} deep
34784 * @param {Boolean} anim
34786 "beforeexpand" : true,
34788 * @event beforecollapse
34789 * Fires before this node is collapsed, return false to cancel.
34790 * @param {Node} this This node
34791 * @param {Boolean} deep
34792 * @param {Boolean} anim
34794 "beforecollapse" : true,
34797 * Fires when this node is expanded
34798 * @param {Node} this This node
34802 * @event disabledchange
34803 * Fires when the disabled status of this node changes
34804 * @param {Node} this This node
34805 * @param {Boolean} disabled
34807 "disabledchange" : true,
34810 * Fires when this node is collapsed
34811 * @param {Node} this This node
34815 * @event beforeclick
34816 * Fires before click processing. Return false to cancel the default action.
34817 * @param {Node} this This node
34818 * @param {Roo.EventObject} e The event object
34820 "beforeclick":true,
34822 * @event checkchange
34823 * Fires when a node with a checkbox's checked property changes
34824 * @param {Node} this This node
34825 * @param {Boolean} checked
34827 "checkchange":true,
34830 * Fires when this node is clicked
34831 * @param {Node} this This node
34832 * @param {Roo.EventObject} e The event object
34837 * Fires when this node is double clicked
34838 * @param {Node} this This node
34839 * @param {Roo.EventObject} e The event object
34843 * @event contextmenu
34844 * Fires when this node is right clicked
34845 * @param {Node} this This node
34846 * @param {Roo.EventObject} e The event object
34848 "contextmenu":true,
34850 * @event beforechildrenrendered
34851 * Fires right before the child nodes for this node are rendered
34852 * @param {Node} this This node
34854 "beforechildrenrendered":true
34857 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34860 * Read-only. The UI for this node
34863 this.ui = new uiClass(this);
34865 // finally support items[]
34866 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34871 Roo.each(this.attributes.items, function(c) {
34872 this.appendChild(Roo.factory(c,Roo.Tree));
34874 delete this.attributes.items;
34879 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34880 preventHScroll: true,
34882 * Returns true if this node is expanded
34883 * @return {Boolean}
34885 isExpanded : function(){
34886 return this.expanded;
34890 * Returns the UI object for this node
34891 * @return {TreeNodeUI}
34893 getUI : function(){
34897 // private override
34898 setFirstChild : function(node){
34899 var of = this.firstChild;
34900 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34901 if(this.childrenRendered && of && node != of){
34902 of.renderIndent(true, true);
34905 this.renderIndent(true, true);
34909 // private override
34910 setLastChild : function(node){
34911 var ol = this.lastChild;
34912 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34913 if(this.childrenRendered && ol && node != ol){
34914 ol.renderIndent(true, true);
34917 this.renderIndent(true, true);
34921 // these methods are overridden to provide lazy rendering support
34922 // private override
34923 appendChild : function()
34925 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34926 if(node && this.childrenRendered){
34929 this.ui.updateExpandIcon();
34933 // private override
34934 removeChild : function(node){
34935 this.ownerTree.getSelectionModel().unselect(node);
34936 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34937 // if it's been rendered remove dom node
34938 if(this.childrenRendered){
34941 if(this.childNodes.length < 1){
34942 this.collapse(false, false);
34944 this.ui.updateExpandIcon();
34946 if(!this.firstChild) {
34947 this.childrenRendered = false;
34952 // private override
34953 insertBefore : function(node, refNode){
34954 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34955 if(newNode && refNode && this.childrenRendered){
34958 this.ui.updateExpandIcon();
34963 * Sets the text for this node
34964 * @param {String} text
34966 setText : function(text){
34967 var oldText = this.text;
34969 this.attributes.text = text;
34970 if(this.rendered){ // event without subscribing
34971 this.ui.onTextChange(this, text, oldText);
34973 this.fireEvent("textchange", this, text, oldText);
34977 * Triggers selection of this node
34979 select : function(){
34980 this.getOwnerTree().getSelectionModel().select(this);
34984 * Triggers deselection of this node
34986 unselect : function(){
34987 this.getOwnerTree().getSelectionModel().unselect(this);
34991 * Returns true if this node is selected
34992 * @return {Boolean}
34994 isSelected : function(){
34995 return this.getOwnerTree().getSelectionModel().isSelected(this);
34999 * Expand this node.
35000 * @param {Boolean} deep (optional) True to expand all children as well
35001 * @param {Boolean} anim (optional) false to cancel the default animation
35002 * @param {Function} callback (optional) A callback to be called when
35003 * expanding this node completes (does not wait for deep expand to complete).
35004 * Called with 1 parameter, this node.
35006 expand : function(deep, anim, callback){
35007 if(!this.expanded){
35008 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35011 if(!this.childrenRendered){
35012 this.renderChildren();
35014 this.expanded = true;
35015 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35016 this.ui.animExpand(function(){
35017 this.fireEvent("expand", this);
35018 if(typeof callback == "function"){
35022 this.expandChildNodes(true);
35024 }.createDelegate(this));
35028 this.fireEvent("expand", this);
35029 if(typeof callback == "function"){
35034 if(typeof callback == "function"){
35039 this.expandChildNodes(true);
35043 isHiddenRoot : function(){
35044 return this.isRoot && !this.getOwnerTree().rootVisible;
35048 * Collapse this node.
35049 * @param {Boolean} deep (optional) True to collapse all children as well
35050 * @param {Boolean} anim (optional) false to cancel the default animation
35052 collapse : function(deep, anim){
35053 if(this.expanded && !this.isHiddenRoot()){
35054 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35057 this.expanded = false;
35058 if((this.getOwnerTree().animate && anim !== false) || anim){
35059 this.ui.animCollapse(function(){
35060 this.fireEvent("collapse", this);
35062 this.collapseChildNodes(true);
35064 }.createDelegate(this));
35067 this.ui.collapse();
35068 this.fireEvent("collapse", this);
35072 var cs = this.childNodes;
35073 for(var i = 0, len = cs.length; i < len; i++) {
35074 cs[i].collapse(true, false);
35080 delayedExpand : function(delay){
35081 if(!this.expandProcId){
35082 this.expandProcId = this.expand.defer(delay, this);
35087 cancelExpand : function(){
35088 if(this.expandProcId){
35089 clearTimeout(this.expandProcId);
35091 this.expandProcId = false;
35095 * Toggles expanded/collapsed state of the node
35097 toggle : function(){
35106 * Ensures all parent nodes are expanded
35108 ensureVisible : function(callback){
35109 var tree = this.getOwnerTree();
35110 tree.expandPath(this.parentNode.getPath(), false, function(){
35111 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35112 Roo.callback(callback);
35113 }.createDelegate(this));
35117 * Expand all child nodes
35118 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35120 expandChildNodes : function(deep){
35121 var cs = this.childNodes;
35122 for(var i = 0, len = cs.length; i < len; i++) {
35123 cs[i].expand(deep);
35128 * Collapse all child nodes
35129 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35131 collapseChildNodes : function(deep){
35132 var cs = this.childNodes;
35133 for(var i = 0, len = cs.length; i < len; i++) {
35134 cs[i].collapse(deep);
35139 * Disables this node
35141 disable : function(){
35142 this.disabled = true;
35144 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35145 this.ui.onDisableChange(this, true);
35147 this.fireEvent("disabledchange", this, true);
35151 * Enables this node
35153 enable : function(){
35154 this.disabled = false;
35155 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35156 this.ui.onDisableChange(this, false);
35158 this.fireEvent("disabledchange", this, false);
35162 renderChildren : function(suppressEvent){
35163 if(suppressEvent !== false){
35164 this.fireEvent("beforechildrenrendered", this);
35166 var cs = this.childNodes;
35167 for(var i = 0, len = cs.length; i < len; i++){
35168 cs[i].render(true);
35170 this.childrenRendered = true;
35174 sort : function(fn, scope){
35175 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35176 if(this.childrenRendered){
35177 var cs = this.childNodes;
35178 for(var i = 0, len = cs.length; i < len; i++){
35179 cs[i].render(true);
35185 render : function(bulkRender){
35186 this.ui.render(bulkRender);
35187 if(!this.rendered){
35188 this.rendered = true;
35190 this.expanded = false;
35191 this.expand(false, false);
35197 renderIndent : function(deep, refresh){
35199 this.ui.childIndent = null;
35201 this.ui.renderIndent();
35202 if(deep === true && this.childrenRendered){
35203 var cs = this.childNodes;
35204 for(var i = 0, len = cs.length; i < len; i++){
35205 cs[i].renderIndent(true, refresh);
35211 * Ext JS Library 1.1.1
35212 * Copyright(c) 2006-2007, Ext JS, LLC.
35214 * Originally Released Under LGPL - original licence link has changed is not relivant.
35217 * <script type="text/javascript">
35221 * @class Roo.tree.AsyncTreeNode
35222 * @extends Roo.tree.TreeNode
35223 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35225 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35227 Roo.tree.AsyncTreeNode = function(config){
35228 this.loaded = false;
35229 this.loading = false;
35230 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35232 * @event beforeload
35233 * Fires before this node is loaded, return false to cancel
35234 * @param {Node} this This node
35236 this.addEvents({'beforeload':true, 'load': true});
35239 * Fires when this node is loaded
35240 * @param {Node} this This node
35243 * The loader used by this node (defaults to using the tree's defined loader)
35248 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35249 expand : function(deep, anim, callback){
35250 if(this.loading){ // if an async load is already running, waiting til it's done
35252 var f = function(){
35253 if(!this.loading){ // done loading
35254 clearInterval(timer);
35255 this.expand(deep, anim, callback);
35257 }.createDelegate(this);
35258 timer = setInterval(f, 200);
35262 if(this.fireEvent("beforeload", this) === false){
35265 this.loading = true;
35266 this.ui.beforeLoad(this);
35267 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35269 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35273 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35277 * Returns true if this node is currently loading
35278 * @return {Boolean}
35280 isLoading : function(){
35281 return this.loading;
35284 loadComplete : function(deep, anim, callback){
35285 this.loading = false;
35286 this.loaded = true;
35287 this.ui.afterLoad(this);
35288 this.fireEvent("load", this);
35289 this.expand(deep, anim, callback);
35293 * Returns true if this node has been loaded
35294 * @return {Boolean}
35296 isLoaded : function(){
35297 return this.loaded;
35300 hasChildNodes : function(){
35301 if(!this.isLeaf() && !this.loaded){
35304 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35309 * Trigger a reload for this node
35310 * @param {Function} callback
35312 reload : function(callback){
35313 this.collapse(false, false);
35314 while(this.firstChild){
35315 this.removeChild(this.firstChild);
35317 this.childrenRendered = false;
35318 this.loaded = false;
35319 if(this.isHiddenRoot()){
35320 this.expanded = false;
35322 this.expand(false, false, callback);
35326 * Ext JS Library 1.1.1
35327 * Copyright(c) 2006-2007, Ext JS, LLC.
35329 * Originally Released Under LGPL - original licence link has changed is not relivant.
35332 * <script type="text/javascript">
35336 * @class Roo.tree.TreeNodeUI
35338 * @param {Object} node The node to render
35339 * The TreeNode UI implementation is separate from the
35340 * tree implementation. Unless you are customizing the tree UI,
35341 * you should never have to use this directly.
35343 Roo.tree.TreeNodeUI = function(node){
35345 this.rendered = false;
35346 this.animating = false;
35347 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35350 Roo.tree.TreeNodeUI.prototype = {
35351 removeChild : function(node){
35353 this.ctNode.removeChild(node.ui.getEl());
35357 beforeLoad : function(){
35358 this.addClass("x-tree-node-loading");
35361 afterLoad : function(){
35362 this.removeClass("x-tree-node-loading");
35365 onTextChange : function(node, text, oldText){
35367 this.textNode.innerHTML = text;
35371 onDisableChange : function(node, state){
35372 this.disabled = state;
35374 this.addClass("x-tree-node-disabled");
35376 this.removeClass("x-tree-node-disabled");
35380 onSelectedChange : function(state){
35383 this.addClass("x-tree-selected");
35386 this.removeClass("x-tree-selected");
35390 onMove : function(tree, node, oldParent, newParent, index, refNode){
35391 this.childIndent = null;
35393 var targetNode = newParent.ui.getContainer();
35394 if(!targetNode){//target not rendered
35395 this.holder = document.createElement("div");
35396 this.holder.appendChild(this.wrap);
35399 var insertBefore = refNode ? refNode.ui.getEl() : null;
35401 targetNode.insertBefore(this.wrap, insertBefore);
35403 targetNode.appendChild(this.wrap);
35405 this.node.renderIndent(true);
35409 addClass : function(cls){
35411 Roo.fly(this.elNode).addClass(cls);
35415 removeClass : function(cls){
35417 Roo.fly(this.elNode).removeClass(cls);
35421 remove : function(){
35423 this.holder = document.createElement("div");
35424 this.holder.appendChild(this.wrap);
35428 fireEvent : function(){
35429 return this.node.fireEvent.apply(this.node, arguments);
35432 initEvents : function(){
35433 this.node.on("move", this.onMove, this);
35434 var E = Roo.EventManager;
35435 var a = this.anchor;
35437 var el = Roo.fly(a, '_treeui');
35439 if(Roo.isOpera){ // opera render bug ignores the CSS
35440 el.setStyle("text-decoration", "none");
35443 el.on("click", this.onClick, this);
35444 el.on("dblclick", this.onDblClick, this);
35447 Roo.EventManager.on(this.checkbox,
35448 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35451 el.on("contextmenu", this.onContextMenu, this);
35453 var icon = Roo.fly(this.iconNode);
35454 icon.on("click", this.onClick, this);
35455 icon.on("dblclick", this.onDblClick, this);
35456 icon.on("contextmenu", this.onContextMenu, this);
35457 E.on(this.ecNode, "click", this.ecClick, this, true);
35459 if(this.node.disabled){
35460 this.addClass("x-tree-node-disabled");
35462 if(this.node.hidden){
35463 this.addClass("x-tree-node-disabled");
35465 var ot = this.node.getOwnerTree();
35466 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35467 if(dd && (!this.node.isRoot || ot.rootVisible)){
35468 Roo.dd.Registry.register(this.elNode, {
35470 handles: this.getDDHandles(),
35476 getDDHandles : function(){
35477 return [this.iconNode, this.textNode];
35482 this.wrap.style.display = "none";
35488 this.wrap.style.display = "";
35492 onContextMenu : function(e){
35493 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35494 e.preventDefault();
35496 this.fireEvent("contextmenu", this.node, e);
35500 onClick : function(e){
35505 if(this.fireEvent("beforeclick", this.node, e) !== false){
35506 if(!this.disabled && this.node.attributes.href){
35507 this.fireEvent("click", this.node, e);
35510 e.preventDefault();
35515 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35516 this.node.toggle();
35519 this.fireEvent("click", this.node, e);
35525 onDblClick : function(e){
35526 e.preventDefault();
35531 this.toggleCheck();
35533 if(!this.animating && this.node.hasChildNodes()){
35534 this.node.toggle();
35536 this.fireEvent("dblclick", this.node, e);
35539 onCheckChange : function(){
35540 var checked = this.checkbox.checked;
35541 this.node.attributes.checked = checked;
35542 this.fireEvent('checkchange', this.node, checked);
35545 ecClick : function(e){
35546 if(!this.animating && this.node.hasChildNodes()){
35547 this.node.toggle();
35551 startDrop : function(){
35552 this.dropping = true;
35555 // delayed drop so the click event doesn't get fired on a drop
35556 endDrop : function(){
35557 setTimeout(function(){
35558 this.dropping = false;
35559 }.createDelegate(this), 50);
35562 expand : function(){
35563 this.updateExpandIcon();
35564 this.ctNode.style.display = "";
35567 focus : function(){
35568 if(!this.node.preventHScroll){
35569 try{this.anchor.focus();
35571 }else if(!Roo.isIE){
35573 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35574 var l = noscroll.scrollLeft;
35575 this.anchor.focus();
35576 noscroll.scrollLeft = l;
35581 toggleCheck : function(value){
35582 var cb = this.checkbox;
35584 cb.checked = (value === undefined ? !cb.checked : value);
35590 this.anchor.blur();
35594 animExpand : function(callback){
35595 var ct = Roo.get(this.ctNode);
35597 if(!this.node.hasChildNodes()){
35598 this.updateExpandIcon();
35599 this.ctNode.style.display = "";
35600 Roo.callback(callback);
35603 this.animating = true;
35604 this.updateExpandIcon();
35607 callback : function(){
35608 this.animating = false;
35609 Roo.callback(callback);
35612 duration: this.node.ownerTree.duration || .25
35616 highlight : function(){
35617 var tree = this.node.getOwnerTree();
35618 Roo.fly(this.wrap).highlight(
35619 tree.hlColor || "C3DAF9",
35620 {endColor: tree.hlBaseColor}
35624 collapse : function(){
35625 this.updateExpandIcon();
35626 this.ctNode.style.display = "none";
35629 animCollapse : function(callback){
35630 var ct = Roo.get(this.ctNode);
35631 ct.enableDisplayMode('block');
35634 this.animating = true;
35635 this.updateExpandIcon();
35638 callback : function(){
35639 this.animating = false;
35640 Roo.callback(callback);
35643 duration: this.node.ownerTree.duration || .25
35647 getContainer : function(){
35648 return this.ctNode;
35651 getEl : function(){
35655 appendDDGhost : function(ghostNode){
35656 ghostNode.appendChild(this.elNode.cloneNode(true));
35659 getDDRepairXY : function(){
35660 return Roo.lib.Dom.getXY(this.iconNode);
35663 onRender : function(){
35667 render : function(bulkRender){
35668 var n = this.node, a = n.attributes;
35669 var targetNode = n.parentNode ?
35670 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35672 if(!this.rendered){
35673 this.rendered = true;
35675 this.renderElements(n, a, targetNode, bulkRender);
35678 if(this.textNode.setAttributeNS){
35679 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35681 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35684 this.textNode.setAttribute("ext:qtip", a.qtip);
35686 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35689 }else if(a.qtipCfg){
35690 a.qtipCfg.target = Roo.id(this.textNode);
35691 Roo.QuickTips.register(a.qtipCfg);
35694 if(!this.node.expanded){
35695 this.updateExpandIcon();
35698 if(bulkRender === true) {
35699 targetNode.appendChild(this.wrap);
35704 renderElements : function(n, a, targetNode, bulkRender)
35706 // add some indent caching, this helps performance when rendering a large tree
35707 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35708 var t = n.getOwnerTree();
35709 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35710 if (typeof(n.attributes.html) != 'undefined') {
35711 txt = n.attributes.html;
35713 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35714 var cb = typeof a.checked == 'boolean';
35715 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35716 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35717 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35718 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35719 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35720 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35721 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35722 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35723 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35724 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35727 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35728 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35729 n.nextSibling.ui.getEl(), buf.join(""));
35731 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35734 this.elNode = this.wrap.childNodes[0];
35735 this.ctNode = this.wrap.childNodes[1];
35736 var cs = this.elNode.childNodes;
35737 this.indentNode = cs[0];
35738 this.ecNode = cs[1];
35739 this.iconNode = cs[2];
35742 this.checkbox = cs[3];
35745 this.anchor = cs[index];
35746 this.textNode = cs[index].firstChild;
35749 getAnchor : function(){
35750 return this.anchor;
35753 getTextEl : function(){
35754 return this.textNode;
35757 getIconEl : function(){
35758 return this.iconNode;
35761 isChecked : function(){
35762 return this.checkbox ? this.checkbox.checked : false;
35765 updateExpandIcon : function(){
35767 var n = this.node, c1, c2;
35768 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35769 var hasChild = n.hasChildNodes();
35773 c1 = "x-tree-node-collapsed";
35774 c2 = "x-tree-node-expanded";
35777 c1 = "x-tree-node-expanded";
35778 c2 = "x-tree-node-collapsed";
35781 this.removeClass("x-tree-node-leaf");
35782 this.wasLeaf = false;
35784 if(this.c1 != c1 || this.c2 != c2){
35785 Roo.fly(this.elNode).replaceClass(c1, c2);
35786 this.c1 = c1; this.c2 = c2;
35789 // this changes non-leafs into leafs if they have no children.
35790 // it's not very rational behaviour..
35792 if(!this.wasLeaf && this.node.leaf){
35793 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35796 this.wasLeaf = true;
35799 var ecc = "x-tree-ec-icon "+cls;
35800 if(this.ecc != ecc){
35801 this.ecNode.className = ecc;
35807 getChildIndent : function(){
35808 if(!this.childIndent){
35812 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35814 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35816 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35821 this.childIndent = buf.join("");
35823 return this.childIndent;
35826 renderIndent : function(){
35829 var p = this.node.parentNode;
35831 indent = p.ui.getChildIndent();
35833 if(this.indentMarkup != indent){ // don't rerender if not required
35834 this.indentNode.innerHTML = indent;
35835 this.indentMarkup = indent;
35837 this.updateExpandIcon();
35842 Roo.tree.RootTreeNodeUI = function(){
35843 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35845 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35846 render : function(){
35847 if(!this.rendered){
35848 var targetNode = this.node.ownerTree.innerCt.dom;
35849 this.node.expanded = true;
35850 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35851 this.wrap = this.ctNode = targetNode.firstChild;
35854 collapse : function(){
35856 expand : function(){
35860 * Ext JS Library 1.1.1
35861 * Copyright(c) 2006-2007, Ext JS, LLC.
35863 * Originally Released Under LGPL - original licence link has changed is not relivant.
35866 * <script type="text/javascript">
35869 * @class Roo.tree.TreeLoader
35870 * @extends Roo.util.Observable
35871 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35872 * nodes from a specified URL. The response must be a javascript Array definition
35873 * who's elements are node definition objects. eg:
35878 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35879 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35886 * The old style respose with just an array is still supported, but not recommended.
35889 * A server request is sent, and child nodes are loaded only when a node is expanded.
35890 * The loading node's id is passed to the server under the parameter name "node" to
35891 * enable the server to produce the correct child nodes.
35893 * To pass extra parameters, an event handler may be attached to the "beforeload"
35894 * event, and the parameters specified in the TreeLoader's baseParams property:
35896 myTreeLoader.on("beforeload", function(treeLoader, node) {
35897 this.baseParams.category = node.attributes.category;
35900 * This would pass an HTTP parameter called "category" to the server containing
35901 * the value of the Node's "category" attribute.
35903 * Creates a new Treeloader.
35904 * @param {Object} config A config object containing config properties.
35906 Roo.tree.TreeLoader = function(config){
35907 this.baseParams = {};
35908 this.requestMethod = "POST";
35909 Roo.apply(this, config);
35914 * @event beforeload
35915 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35916 * @param {Object} This TreeLoader object.
35917 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35918 * @param {Object} callback The callback function specified in the {@link #load} call.
35923 * Fires when the node has been successfuly loaded.
35924 * @param {Object} This TreeLoader object.
35925 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35926 * @param {Object} response The response object containing the data from the server.
35930 * @event loadexception
35931 * Fires if the network request failed.
35932 * @param {Object} This TreeLoader object.
35933 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35934 * @param {Object} response The response object containing the data from the server.
35936 loadexception : true,
35939 * Fires before a node is created, enabling you to return custom Node types
35940 * @param {Object} This TreeLoader object.
35941 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35946 Roo.tree.TreeLoader.superclass.constructor.call(this);
35949 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35951 * @cfg {String} dataUrl The URL from which to request a Json string which
35952 * specifies an array of node definition object representing the child nodes
35956 * @cfg {String} requestMethod either GET or POST
35957 * defaults to POST (due to BC)
35961 * @cfg {Object} baseParams (optional) An object containing properties which
35962 * specify HTTP parameters to be passed to each request for child nodes.
35965 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35966 * created by this loader. If the attributes sent by the server have an attribute in this object,
35967 * they take priority.
35970 * @cfg {Object} uiProviders (optional) An object containing properties which
35972 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35973 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35974 * <i>uiProvider</i> attribute of a returned child node is a string rather
35975 * than a reference to a TreeNodeUI implementation, this that string value
35976 * is used as a property name in the uiProviders object. You can define the provider named
35977 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35982 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35983 * child nodes before loading.
35985 clearOnLoad : true,
35988 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35989 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35990 * Grid query { data : [ .....] }
35995 * @cfg {String} queryParam (optional)
35996 * Name of the query as it will be passed on the querystring (defaults to 'node')
35997 * eg. the request will be ?node=[id]
36004 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36005 * This is called automatically when a node is expanded, but may be used to reload
36006 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36007 * @param {Roo.tree.TreeNode} node
36008 * @param {Function} callback
36010 load : function(node, callback){
36011 if(this.clearOnLoad){
36012 while(node.firstChild){
36013 node.removeChild(node.firstChild);
36016 if(node.attributes.children){ // preloaded json children
36017 var cs = node.attributes.children;
36018 for(var i = 0, len = cs.length; i < len; i++){
36019 node.appendChild(this.createNode(cs[i]));
36021 if(typeof callback == "function"){
36024 }else if(this.dataUrl){
36025 this.requestData(node, callback);
36029 getParams: function(node){
36030 var buf = [], bp = this.baseParams;
36031 for(var key in bp){
36032 if(typeof bp[key] != "function"){
36033 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36036 var n = this.queryParam === false ? 'node' : this.queryParam;
36037 buf.push(n + "=", encodeURIComponent(node.id));
36038 return buf.join("");
36041 requestData : function(node, callback){
36042 if(this.fireEvent("beforeload", this, node, callback) !== false){
36043 this.transId = Roo.Ajax.request({
36044 method:this.requestMethod,
36045 url: this.dataUrl||this.url,
36046 success: this.handleResponse,
36047 failure: this.handleFailure,
36049 argument: {callback: callback, node: node},
36050 params: this.getParams(node)
36053 // if the load is cancelled, make sure we notify
36054 // the node that we are done
36055 if(typeof callback == "function"){
36061 isLoading : function(){
36062 return this.transId ? true : false;
36065 abort : function(){
36066 if(this.isLoading()){
36067 Roo.Ajax.abort(this.transId);
36072 createNode : function(attr)
36074 // apply baseAttrs, nice idea Corey!
36075 if(this.baseAttrs){
36076 Roo.applyIf(attr, this.baseAttrs);
36078 if(this.applyLoader !== false){
36079 attr.loader = this;
36081 // uiProvider = depreciated..
36083 if(typeof(attr.uiProvider) == 'string'){
36084 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36085 /** eval:var:attr */ eval(attr.uiProvider);
36087 if(typeof(this.uiProviders['default']) != 'undefined') {
36088 attr.uiProvider = this.uiProviders['default'];
36091 this.fireEvent('create', this, attr);
36093 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36095 new Roo.tree.TreeNode(attr) :
36096 new Roo.tree.AsyncTreeNode(attr));
36099 processResponse : function(response, node, callback)
36101 var json = response.responseText;
36104 var o = Roo.decode(json);
36106 if (this.root === false && typeof(o.success) != undefined) {
36107 this.root = 'data'; // the default behaviour for list like data..
36110 if (this.root !== false && !o.success) {
36111 // it's a failure condition.
36112 var a = response.argument;
36113 this.fireEvent("loadexception", this, a.node, response);
36114 Roo.log("Load failed - should have a handler really");
36120 if (this.root !== false) {
36124 for(var i = 0, len = o.length; i < len; i++){
36125 var n = this.createNode(o[i]);
36127 node.appendChild(n);
36130 if(typeof callback == "function"){
36131 callback(this, node);
36134 this.handleFailure(response);
36138 handleResponse : function(response){
36139 this.transId = false;
36140 var a = response.argument;
36141 this.processResponse(response, a.node, a.callback);
36142 this.fireEvent("load", this, a.node, response);
36145 handleFailure : function(response)
36147 // should handle failure better..
36148 this.transId = false;
36149 var a = response.argument;
36150 this.fireEvent("loadexception", this, a.node, response);
36151 if(typeof a.callback == "function"){
36152 a.callback(this, a.node);
36157 * Ext JS Library 1.1.1
36158 * Copyright(c) 2006-2007, Ext JS, LLC.
36160 * Originally Released Under LGPL - original licence link has changed is not relivant.
36163 * <script type="text/javascript">
36167 * @class Roo.tree.TreeFilter
36168 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36169 * @param {TreePanel} tree
36170 * @param {Object} config (optional)
36172 Roo.tree.TreeFilter = function(tree, config){
36174 this.filtered = {};
36175 Roo.apply(this, config);
36178 Roo.tree.TreeFilter.prototype = {
36185 * Filter the data by a specific attribute.
36186 * @param {String/RegExp} value Either string that the attribute value
36187 * should start with or a RegExp to test against the attribute
36188 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36189 * @param {TreeNode} startNode (optional) The node to start the filter at.
36191 filter : function(value, attr, startNode){
36192 attr = attr || "text";
36194 if(typeof value == "string"){
36195 var vlen = value.length;
36196 // auto clear empty filter
36197 if(vlen == 0 && this.clearBlank){
36201 value = value.toLowerCase();
36203 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36205 }else if(value.exec){ // regex?
36207 return value.test(n.attributes[attr]);
36210 throw 'Illegal filter type, must be string or regex';
36212 this.filterBy(f, null, startNode);
36216 * Filter by a function. The passed function will be called with each
36217 * node in the tree (or from the startNode). If the function returns true, the node is kept
36218 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36219 * @param {Function} fn The filter function
36220 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36222 filterBy : function(fn, scope, startNode){
36223 startNode = startNode || this.tree.root;
36224 if(this.autoClear){
36227 var af = this.filtered, rv = this.reverse;
36228 var f = function(n){
36229 if(n == startNode){
36235 var m = fn.call(scope || n, n);
36243 startNode.cascade(f);
36246 if(typeof id != "function"){
36248 if(n && n.parentNode){
36249 n.parentNode.removeChild(n);
36257 * Clears the current filter. Note: with the "remove" option
36258 * set a filter cannot be cleared.
36260 clear : function(){
36262 var af = this.filtered;
36264 if(typeof id != "function"){
36271 this.filtered = {};
36276 * Ext JS Library 1.1.1
36277 * Copyright(c) 2006-2007, Ext JS, LLC.
36279 * Originally Released Under LGPL - original licence link has changed is not relivant.
36282 * <script type="text/javascript">
36287 * @class Roo.tree.TreeSorter
36288 * Provides sorting of nodes in a TreePanel
36290 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36291 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36292 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36293 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36294 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36295 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36297 * @param {TreePanel} tree
36298 * @param {Object} config
36300 Roo.tree.TreeSorter = function(tree, config){
36301 Roo.apply(this, config);
36302 tree.on("beforechildrenrendered", this.doSort, this);
36303 tree.on("append", this.updateSort, this);
36304 tree.on("insert", this.updateSort, this);
36306 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36307 var p = this.property || "text";
36308 var sortType = this.sortType;
36309 var fs = this.folderSort;
36310 var cs = this.caseSensitive === true;
36311 var leafAttr = this.leafAttr || 'leaf';
36313 this.sortFn = function(n1, n2){
36315 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36318 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36322 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36323 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36325 return dsc ? +1 : -1;
36327 return dsc ? -1 : +1;
36334 Roo.tree.TreeSorter.prototype = {
36335 doSort : function(node){
36336 node.sort(this.sortFn);
36339 compareNodes : function(n1, n2){
36340 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36343 updateSort : function(tree, node){
36344 if(node.childrenRendered){
36345 this.doSort.defer(1, this, [node]);
36350 * Ext JS Library 1.1.1
36351 * Copyright(c) 2006-2007, Ext JS, LLC.
36353 * Originally Released Under LGPL - original licence link has changed is not relivant.
36356 * <script type="text/javascript">
36359 if(Roo.dd.DropZone){
36361 Roo.tree.TreeDropZone = function(tree, config){
36362 this.allowParentInsert = false;
36363 this.allowContainerDrop = false;
36364 this.appendOnly = false;
36365 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36367 this.lastInsertClass = "x-tree-no-status";
36368 this.dragOverData = {};
36371 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36372 ddGroup : "TreeDD",
36375 expandDelay : 1000,
36377 expandNode : function(node){
36378 if(node.hasChildNodes() && !node.isExpanded()){
36379 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36383 queueExpand : function(node){
36384 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36387 cancelExpand : function(){
36388 if(this.expandProcId){
36389 clearTimeout(this.expandProcId);
36390 this.expandProcId = false;
36394 isValidDropPoint : function(n, pt, dd, e, data){
36395 if(!n || !data){ return false; }
36396 var targetNode = n.node;
36397 var dropNode = data.node;
36398 // default drop rules
36399 if(!(targetNode && targetNode.isTarget && pt)){
36402 if(pt == "append" && targetNode.allowChildren === false){
36405 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36408 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36411 // reuse the object
36412 var overEvent = this.dragOverData;
36413 overEvent.tree = this.tree;
36414 overEvent.target = targetNode;
36415 overEvent.data = data;
36416 overEvent.point = pt;
36417 overEvent.source = dd;
36418 overEvent.rawEvent = e;
36419 overEvent.dropNode = dropNode;
36420 overEvent.cancel = false;
36421 var result = this.tree.fireEvent("nodedragover", overEvent);
36422 return overEvent.cancel === false && result !== false;
36425 getDropPoint : function(e, n, dd)
36429 return tn.allowChildren !== false ? "append" : false; // always append for root
36431 var dragEl = n.ddel;
36432 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36433 var y = Roo.lib.Event.getPageY(e);
36434 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36436 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36437 var noAppend = tn.allowChildren === false;
36438 if(this.appendOnly || tn.parentNode.allowChildren === false){
36439 return noAppend ? false : "append";
36441 var noBelow = false;
36442 if(!this.allowParentInsert){
36443 noBelow = tn.hasChildNodes() && tn.isExpanded();
36445 var q = (b - t) / (noAppend ? 2 : 3);
36446 if(y >= t && y < (t + q)){
36448 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36455 onNodeEnter : function(n, dd, e, data)
36457 this.cancelExpand();
36460 onNodeOver : function(n, dd, e, data)
36463 var pt = this.getDropPoint(e, n, dd);
36466 // auto node expand check
36467 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36468 this.queueExpand(node);
36469 }else if(pt != "append"){
36470 this.cancelExpand();
36473 // set the insert point style on the target node
36474 var returnCls = this.dropNotAllowed;
36475 if(this.isValidDropPoint(n, pt, dd, e, data)){
36480 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36481 cls = "x-tree-drag-insert-above";
36482 }else if(pt == "below"){
36483 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36484 cls = "x-tree-drag-insert-below";
36486 returnCls = "x-tree-drop-ok-append";
36487 cls = "x-tree-drag-append";
36489 if(this.lastInsertClass != cls){
36490 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36491 this.lastInsertClass = cls;
36498 onNodeOut : function(n, dd, e, data){
36500 this.cancelExpand();
36501 this.removeDropIndicators(n);
36504 onNodeDrop : function(n, dd, e, data){
36505 var point = this.getDropPoint(e, n, dd);
36506 var targetNode = n.node;
36507 targetNode.ui.startDrop();
36508 if(!this.isValidDropPoint(n, point, dd, e, data)){
36509 targetNode.ui.endDrop();
36512 // first try to find the drop node
36513 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36516 target: targetNode,
36521 dropNode: dropNode,
36524 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36525 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36526 targetNode.ui.endDrop();
36529 // allow target changing
36530 targetNode = dropEvent.target;
36531 if(point == "append" && !targetNode.isExpanded()){
36532 targetNode.expand(false, null, function(){
36533 this.completeDrop(dropEvent);
36534 }.createDelegate(this));
36536 this.completeDrop(dropEvent);
36541 completeDrop : function(de){
36542 var ns = de.dropNode, p = de.point, t = de.target;
36543 if(!(ns instanceof Array)){
36547 for(var i = 0, len = ns.length; i < len; i++){
36550 t.parentNode.insertBefore(n, t);
36551 }else if(p == "below"){
36552 t.parentNode.insertBefore(n, t.nextSibling);
36558 if(this.tree.hlDrop){
36562 this.tree.fireEvent("nodedrop", de);
36565 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36566 if(this.tree.hlDrop){
36567 dropNode.ui.focus();
36568 dropNode.ui.highlight();
36570 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36573 getTree : function(){
36577 removeDropIndicators : function(n){
36580 Roo.fly(el).removeClass([
36581 "x-tree-drag-insert-above",
36582 "x-tree-drag-insert-below",
36583 "x-tree-drag-append"]);
36584 this.lastInsertClass = "_noclass";
36588 beforeDragDrop : function(target, e, id){
36589 this.cancelExpand();
36593 afterRepair : function(data){
36594 if(data && Roo.enableFx){
36595 data.node.ui.highlight();
36605 * Ext JS Library 1.1.1
36606 * Copyright(c) 2006-2007, Ext JS, LLC.
36608 * Originally Released Under LGPL - original licence link has changed is not relivant.
36611 * <script type="text/javascript">
36615 if(Roo.dd.DragZone){
36616 Roo.tree.TreeDragZone = function(tree, config){
36617 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36621 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36622 ddGroup : "TreeDD",
36624 onBeforeDrag : function(data, e){
36626 return n && n.draggable && !n.disabled;
36630 onInitDrag : function(e){
36631 var data = this.dragData;
36632 this.tree.getSelectionModel().select(data.node);
36633 this.proxy.update("");
36634 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36635 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36638 getRepairXY : function(e, data){
36639 return data.node.ui.getDDRepairXY();
36642 onEndDrag : function(data, e){
36643 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36648 onValidDrop : function(dd, e, id){
36649 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36653 beforeInvalidDrop : function(e, id){
36654 // this scrolls the original position back into view
36655 var sm = this.tree.getSelectionModel();
36656 sm.clearSelections();
36657 sm.select(this.dragData.node);
36662 * Ext JS Library 1.1.1
36663 * Copyright(c) 2006-2007, Ext JS, LLC.
36665 * Originally Released Under LGPL - original licence link has changed is not relivant.
36668 * <script type="text/javascript">
36671 * @class Roo.tree.TreeEditor
36672 * @extends Roo.Editor
36673 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36674 * as the editor field.
36676 * @param {Object} config (used to be the tree panel.)
36677 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36679 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36680 * @cfg {Roo.form.TextField|Object} field The field configuration
36684 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36687 if (oldconfig) { // old style..
36688 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36691 tree = config.tree;
36692 config.field = config.field || {};
36693 config.field.xtype = 'TextField';
36694 field = Roo.factory(config.field, Roo.form);
36696 config = config || {};
36701 * @event beforenodeedit
36702 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36703 * false from the handler of this event.
36704 * @param {Editor} this
36705 * @param {Roo.tree.Node} node
36707 "beforenodeedit" : true
36711 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36715 tree.on('beforeclick', this.beforeNodeClick, this);
36716 tree.getTreeEl().on('mousedown', this.hide, this);
36717 this.on('complete', this.updateNode, this);
36718 this.on('beforestartedit', this.fitToTree, this);
36719 this.on('startedit', this.bindScroll, this, {delay:10});
36720 this.on('specialkey', this.onSpecialKey, this);
36723 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36725 * @cfg {String} alignment
36726 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36732 * @cfg {Boolean} hideEl
36733 * True to hide the bound element while the editor is displayed (defaults to false)
36737 * @cfg {String} cls
36738 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36740 cls: "x-small-editor x-tree-editor",
36742 * @cfg {Boolean} shim
36743 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36749 * @cfg {Number} maxWidth
36750 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36751 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36752 * scroll and client offsets into account prior to each edit.
36759 fitToTree : function(ed, el){
36760 var td = this.tree.getTreeEl().dom, nd = el.dom;
36761 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36762 td.scrollLeft = nd.offsetLeft;
36766 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36767 this.setSize(w, '');
36769 return this.fireEvent('beforenodeedit', this, this.editNode);
36774 triggerEdit : function(node){
36775 this.completeEdit();
36776 this.editNode = node;
36777 this.startEdit(node.ui.textNode, node.text);
36781 bindScroll : function(){
36782 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36786 beforeNodeClick : function(node, e){
36787 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36788 this.lastClick = new Date();
36789 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36791 this.triggerEdit(node);
36798 updateNode : function(ed, value){
36799 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36800 this.editNode.setText(value);
36804 onHide : function(){
36805 Roo.tree.TreeEditor.superclass.onHide.call(this);
36807 this.editNode.ui.focus();
36812 onSpecialKey : function(field, e){
36813 var k = e.getKey();
36817 }else if(k == e.ENTER && !e.hasModifier()){
36819 this.completeEdit();
36822 });//<Script type="text/javascript">
36825 * Ext JS Library 1.1.1
36826 * Copyright(c) 2006-2007, Ext JS, LLC.
36828 * Originally Released Under LGPL - original licence link has changed is not relivant.
36831 * <script type="text/javascript">
36835 * Not documented??? - probably should be...
36838 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36839 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36841 renderElements : function(n, a, targetNode, bulkRender){
36842 //consel.log("renderElements?");
36843 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36845 var t = n.getOwnerTree();
36846 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36848 var cols = t.columns;
36849 var bw = t.borderWidth;
36851 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36852 var cb = typeof a.checked == "boolean";
36853 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36854 var colcls = 'x-t-' + tid + '-c0';
36856 '<li class="x-tree-node">',
36859 '<div class="x-tree-node-el ', a.cls,'">',
36861 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36864 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36865 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36866 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36867 (a.icon ? ' x-tree-node-inline-icon' : ''),
36868 (a.iconCls ? ' '+a.iconCls : ''),
36869 '" unselectable="on" />',
36870 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36871 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36873 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36874 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36875 '<span unselectable="on" qtip="' + tx + '">',
36879 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36880 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36882 for(var i = 1, len = cols.length; i < len; i++){
36884 colcls = 'x-t-' + tid + '-c' +i;
36885 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36886 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36887 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36893 '<div class="x-clear"></div></div>',
36894 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36897 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36898 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36899 n.nextSibling.ui.getEl(), buf.join(""));
36901 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36903 var el = this.wrap.firstChild;
36905 this.elNode = el.firstChild;
36906 this.ranchor = el.childNodes[1];
36907 this.ctNode = this.wrap.childNodes[1];
36908 var cs = el.firstChild.childNodes;
36909 this.indentNode = cs[0];
36910 this.ecNode = cs[1];
36911 this.iconNode = cs[2];
36914 this.checkbox = cs[3];
36917 this.anchor = cs[index];
36919 this.textNode = cs[index].firstChild;
36921 //el.on("click", this.onClick, this);
36922 //el.on("dblclick", this.onDblClick, this);
36925 // console.log(this);
36927 initEvents : function(){
36928 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36931 var a = this.ranchor;
36933 var el = Roo.get(a);
36935 if(Roo.isOpera){ // opera render bug ignores the CSS
36936 el.setStyle("text-decoration", "none");
36939 el.on("click", this.onClick, this);
36940 el.on("dblclick", this.onDblClick, this);
36941 el.on("contextmenu", this.onContextMenu, this);
36945 /*onSelectedChange : function(state){
36948 this.addClass("x-tree-selected");
36951 this.removeClass("x-tree-selected");
36954 addClass : function(cls){
36956 Roo.fly(this.elRow).addClass(cls);
36962 removeClass : function(cls){
36964 Roo.fly(this.elRow).removeClass(cls);
36970 });//<Script type="text/javascript">
36974 * Ext JS Library 1.1.1
36975 * Copyright(c) 2006-2007, Ext JS, LLC.
36977 * Originally Released Under LGPL - original licence link has changed is not relivant.
36980 * <script type="text/javascript">
36985 * @class Roo.tree.ColumnTree
36986 * @extends Roo.data.TreePanel
36987 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36988 * @cfg {int} borderWidth compined right/left border allowance
36990 * @param {String/HTMLElement/Element} el The container element
36991 * @param {Object} config
36993 Roo.tree.ColumnTree = function(el, config)
36995 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36999 * Fire this event on a container when it resizes
37000 * @param {int} w Width
37001 * @param {int} h Height
37005 this.on('resize', this.onResize, this);
37008 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37012 borderWidth: Roo.isBorderBox ? 0 : 2,
37015 render : function(){
37016 // add the header.....
37018 Roo.tree.ColumnTree.superclass.render.apply(this);
37020 this.el.addClass('x-column-tree');
37022 this.headers = this.el.createChild(
37023 {cls:'x-tree-headers'},this.innerCt.dom);
37025 var cols = this.columns, c;
37026 var totalWidth = 0;
37028 var len = cols.length;
37029 for(var i = 0; i < len; i++){
37031 totalWidth += c.width;
37032 this.headEls.push(this.headers.createChild({
37033 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37035 cls:'x-tree-hd-text',
37038 style:'width:'+(c.width-this.borderWidth)+'px;'
37041 this.headers.createChild({cls:'x-clear'});
37042 // prevent floats from wrapping when clipped
37043 this.headers.setWidth(totalWidth);
37044 //this.innerCt.setWidth(totalWidth);
37045 this.innerCt.setStyle({ overflow: 'auto' });
37046 this.onResize(this.width, this.height);
37050 onResize : function(w,h)
37055 this.innerCt.setWidth(this.width);
37056 this.innerCt.setHeight(this.height-20);
37059 var cols = this.columns, c;
37060 var totalWidth = 0;
37062 var len = cols.length;
37063 for(var i = 0; i < len; i++){
37065 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37066 // it's the expander..
37067 expEl = this.headEls[i];
37070 totalWidth += c.width;
37074 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37076 this.headers.setWidth(w-20);
37085 * Ext JS Library 1.1.1
37086 * Copyright(c) 2006-2007, Ext JS, LLC.
37088 * Originally Released Under LGPL - original licence link has changed is not relivant.
37091 * <script type="text/javascript">
37095 * @class Roo.menu.Menu
37096 * @extends Roo.util.Observable
37097 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37098 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37100 * Creates a new Menu
37101 * @param {Object} config Configuration options
37103 Roo.menu.Menu = function(config){
37104 Roo.apply(this, config);
37105 this.id = this.id || Roo.id();
37108 * @event beforeshow
37109 * Fires before this menu is displayed
37110 * @param {Roo.menu.Menu} this
37114 * @event beforehide
37115 * Fires before this menu is hidden
37116 * @param {Roo.menu.Menu} this
37121 * Fires after this menu is displayed
37122 * @param {Roo.menu.Menu} this
37127 * Fires after this menu is hidden
37128 * @param {Roo.menu.Menu} this
37133 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37134 * @param {Roo.menu.Menu} this
37135 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37136 * @param {Roo.EventObject} e
37141 * Fires when the mouse is hovering over this menu
37142 * @param {Roo.menu.Menu} this
37143 * @param {Roo.EventObject} e
37144 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37149 * Fires when the mouse exits this menu
37150 * @param {Roo.menu.Menu} this
37151 * @param {Roo.EventObject} e
37152 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37157 * Fires when a menu item contained in this menu is clicked
37158 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37159 * @param {Roo.EventObject} e
37163 if (this.registerMenu) {
37164 Roo.menu.MenuMgr.register(this);
37167 var mis = this.items;
37168 this.items = new Roo.util.MixedCollection();
37170 this.add.apply(this, mis);
37174 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37176 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37180 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37181 * for bottom-right shadow (defaults to "sides")
37185 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37186 * this menu (defaults to "tl-tr?")
37188 subMenuAlign : "tl-tr?",
37190 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37191 * relative to its element of origin (defaults to "tl-bl?")
37193 defaultAlign : "tl-bl?",
37195 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37197 allowOtherMenus : false,
37199 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37201 registerMenu : true,
37206 render : function(){
37210 var el = this.el = new Roo.Layer({
37212 shadow:this.shadow,
37214 parentEl: this.parentEl || document.body,
37218 this.keyNav = new Roo.menu.MenuNav(this);
37221 el.addClass("x-menu-plain");
37224 el.addClass(this.cls);
37226 // generic focus element
37227 this.focusEl = el.createChild({
37228 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37230 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37231 //disabling touch- as it's causing issues ..
37232 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37233 ul.on('click' , this.onClick, this);
37236 ul.on("mouseover", this.onMouseOver, this);
37237 ul.on("mouseout", this.onMouseOut, this);
37238 this.items.each(function(item){
37243 var li = document.createElement("li");
37244 li.className = "x-menu-list-item";
37245 ul.dom.appendChild(li);
37246 item.render(li, this);
37253 autoWidth : function(){
37254 var el = this.el, ul = this.ul;
37258 var w = this.width;
37261 }else if(Roo.isIE){
37262 el.setWidth(this.minWidth);
37263 var t = el.dom.offsetWidth; // force recalc
37264 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37269 delayAutoWidth : function(){
37272 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37274 this.awTask.delay(20);
37279 findTargetItem : function(e){
37280 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37281 if(t && t.menuItemId){
37282 return this.items.get(t.menuItemId);
37287 onClick : function(e){
37288 Roo.log("menu.onClick");
37289 var t = this.findTargetItem(e);
37294 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37295 if(t == this.activeItem && t.shouldDeactivate(e)){
37296 this.activeItem.deactivate();
37297 delete this.activeItem;
37301 this.setActiveItem(t, true);
37309 this.fireEvent("click", this, t, e);
37313 setActiveItem : function(item, autoExpand){
37314 if(item != this.activeItem){
37315 if(this.activeItem){
37316 this.activeItem.deactivate();
37318 this.activeItem = item;
37319 item.activate(autoExpand);
37320 }else if(autoExpand){
37326 tryActivate : function(start, step){
37327 var items = this.items;
37328 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37329 var item = items.get(i);
37330 if(!item.disabled && item.canActivate){
37331 this.setActiveItem(item, false);
37339 onMouseOver : function(e){
37341 if(t = this.findTargetItem(e)){
37342 if(t.canActivate && !t.disabled){
37343 this.setActiveItem(t, true);
37346 this.fireEvent("mouseover", this, e, t);
37350 onMouseOut : function(e){
37352 if(t = this.findTargetItem(e)){
37353 if(t == this.activeItem && t.shouldDeactivate(e)){
37354 this.activeItem.deactivate();
37355 delete this.activeItem;
37358 this.fireEvent("mouseout", this, e, t);
37362 * Read-only. Returns true if the menu is currently displayed, else false.
37365 isVisible : function(){
37366 return this.el && !this.hidden;
37370 * Displays this menu relative to another element
37371 * @param {String/HTMLElement/Roo.Element} element The element to align to
37372 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37373 * the element (defaults to this.defaultAlign)
37374 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37376 show : function(el, pos, parentMenu){
37377 this.parentMenu = parentMenu;
37381 this.fireEvent("beforeshow", this);
37382 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37386 * Displays this menu at a specific xy position
37387 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37388 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37390 showAt : function(xy, parentMenu, /* private: */_e){
37391 this.parentMenu = parentMenu;
37396 this.fireEvent("beforeshow", this);
37397 xy = this.el.adjustForConstraints(xy);
37401 this.hidden = false;
37403 this.fireEvent("show", this);
37406 focus : function(){
37408 this.doFocus.defer(50, this);
37412 doFocus : function(){
37414 this.focusEl.focus();
37419 * Hides this menu and optionally all parent menus
37420 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37422 hide : function(deep){
37423 if(this.el && this.isVisible()){
37424 this.fireEvent("beforehide", this);
37425 if(this.activeItem){
37426 this.activeItem.deactivate();
37427 this.activeItem = null;
37430 this.hidden = true;
37431 this.fireEvent("hide", this);
37433 if(deep === true && this.parentMenu){
37434 this.parentMenu.hide(true);
37439 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37440 * Any of the following are valid:
37442 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37443 * <li>An HTMLElement object which will be converted to a menu item</li>
37444 * <li>A menu item config object that will be created as a new menu item</li>
37445 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37446 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37451 var menu = new Roo.menu.Menu();
37453 // Create a menu item to add by reference
37454 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37456 // Add a bunch of items at once using different methods.
37457 // Only the last item added will be returned.
37458 var item = menu.add(
37459 menuItem, // add existing item by ref
37460 'Dynamic Item', // new TextItem
37461 '-', // new separator
37462 { text: 'Config Item' } // new item by config
37465 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37466 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37469 var a = arguments, l = a.length, item;
37470 for(var i = 0; i < l; i++){
37472 if ((typeof(el) == "object") && el.xtype && el.xns) {
37473 el = Roo.factory(el, Roo.menu);
37476 if(el.render){ // some kind of Item
37477 item = this.addItem(el);
37478 }else if(typeof el == "string"){ // string
37479 if(el == "separator" || el == "-"){
37480 item = this.addSeparator();
37482 item = this.addText(el);
37484 }else if(el.tagName || el.el){ // element
37485 item = this.addElement(el);
37486 }else if(typeof el == "object"){ // must be menu item config?
37487 item = this.addMenuItem(el);
37494 * Returns this menu's underlying {@link Roo.Element} object
37495 * @return {Roo.Element} The element
37497 getEl : function(){
37505 * Adds a separator bar to the menu
37506 * @return {Roo.menu.Item} The menu item that was added
37508 addSeparator : function(){
37509 return this.addItem(new Roo.menu.Separator());
37513 * Adds an {@link Roo.Element} object to the menu
37514 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37515 * @return {Roo.menu.Item} The menu item that was added
37517 addElement : function(el){
37518 return this.addItem(new Roo.menu.BaseItem(el));
37522 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37523 * @param {Roo.menu.Item} item The menu item to add
37524 * @return {Roo.menu.Item} The menu item that was added
37526 addItem : function(item){
37527 this.items.add(item);
37529 var li = document.createElement("li");
37530 li.className = "x-menu-list-item";
37531 this.ul.dom.appendChild(li);
37532 item.render(li, this);
37533 this.delayAutoWidth();
37539 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37540 * @param {Object} config A MenuItem config object
37541 * @return {Roo.menu.Item} The menu item that was added
37543 addMenuItem : function(config){
37544 if(!(config instanceof Roo.menu.Item)){
37545 if(typeof config.checked == "boolean"){ // must be check menu item config?
37546 config = new Roo.menu.CheckItem(config);
37548 config = new Roo.menu.Item(config);
37551 return this.addItem(config);
37555 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37556 * @param {String} text The text to display in the menu item
37557 * @return {Roo.menu.Item} The menu item that was added
37559 addText : function(text){
37560 return this.addItem(new Roo.menu.TextItem({ text : text }));
37564 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37565 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37566 * @param {Roo.menu.Item} item The menu item to add
37567 * @return {Roo.menu.Item} The menu item that was added
37569 insert : function(index, item){
37570 this.items.insert(index, item);
37572 var li = document.createElement("li");
37573 li.className = "x-menu-list-item";
37574 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37575 item.render(li, this);
37576 this.delayAutoWidth();
37582 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37583 * @param {Roo.menu.Item} item The menu item to remove
37585 remove : function(item){
37586 this.items.removeKey(item.id);
37591 * Removes and destroys all items in the menu
37593 removeAll : function(){
37595 while(f = this.items.first()){
37601 // MenuNav is a private utility class used internally by the Menu
37602 Roo.menu.MenuNav = function(menu){
37603 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37604 this.scope = this.menu = menu;
37607 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37608 doRelay : function(e, h){
37609 var k = e.getKey();
37610 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37611 this.menu.tryActivate(0, 1);
37614 return h.call(this.scope || this, e, this.menu);
37617 up : function(e, m){
37618 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37619 m.tryActivate(m.items.length-1, -1);
37623 down : function(e, m){
37624 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37625 m.tryActivate(0, 1);
37629 right : function(e, m){
37631 m.activeItem.expandMenu(true);
37635 left : function(e, m){
37637 if(m.parentMenu && m.parentMenu.activeItem){
37638 m.parentMenu.activeItem.activate();
37642 enter : function(e, m){
37644 e.stopPropagation();
37645 m.activeItem.onClick(e);
37646 m.fireEvent("click", this, m.activeItem);
37652 * Ext JS Library 1.1.1
37653 * Copyright(c) 2006-2007, Ext JS, LLC.
37655 * Originally Released Under LGPL - original licence link has changed is not relivant.
37658 * <script type="text/javascript">
37662 * @class Roo.menu.MenuMgr
37663 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37666 Roo.menu.MenuMgr = function(){
37667 var menus, active, groups = {}, attached = false, lastShow = new Date();
37669 // private - called when first menu is created
37672 active = new Roo.util.MixedCollection();
37673 Roo.get(document).addKeyListener(27, function(){
37674 if(active.length > 0){
37681 function hideAll(){
37682 if(active && active.length > 0){
37683 var c = active.clone();
37684 c.each(function(m){
37691 function onHide(m){
37693 if(active.length < 1){
37694 Roo.get(document).un("mousedown", onMouseDown);
37700 function onShow(m){
37701 var last = active.last();
37702 lastShow = new Date();
37705 Roo.get(document).on("mousedown", onMouseDown);
37709 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37710 m.parentMenu.activeChild = m;
37711 }else if(last && last.isVisible()){
37712 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37717 function onBeforeHide(m){
37719 m.activeChild.hide();
37721 if(m.autoHideTimer){
37722 clearTimeout(m.autoHideTimer);
37723 delete m.autoHideTimer;
37728 function onBeforeShow(m){
37729 var pm = m.parentMenu;
37730 if(!pm && !m.allowOtherMenus){
37732 }else if(pm && pm.activeChild && active != m){
37733 pm.activeChild.hide();
37738 function onMouseDown(e){
37739 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37745 function onBeforeCheck(mi, state){
37747 var g = groups[mi.group];
37748 for(var i = 0, l = g.length; i < l; i++){
37750 g[i].setChecked(false);
37759 * Hides all menus that are currently visible
37761 hideAll : function(){
37766 register : function(menu){
37770 menus[menu.id] = menu;
37771 menu.on("beforehide", onBeforeHide);
37772 menu.on("hide", onHide);
37773 menu.on("beforeshow", onBeforeShow);
37774 menu.on("show", onShow);
37775 var g = menu.group;
37776 if(g && menu.events["checkchange"]){
37780 groups[g].push(menu);
37781 menu.on("checkchange", onCheck);
37786 * Returns a {@link Roo.menu.Menu} object
37787 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37788 * be used to generate and return a new Menu instance.
37790 get : function(menu){
37791 if(typeof menu == "string"){ // menu id
37792 return menus[menu];
37793 }else if(menu.events){ // menu instance
37795 }else if(typeof menu.length == 'number'){ // array of menu items?
37796 return new Roo.menu.Menu({items:menu});
37797 }else{ // otherwise, must be a config
37798 return new Roo.menu.Menu(menu);
37803 unregister : function(menu){
37804 delete menus[menu.id];
37805 menu.un("beforehide", onBeforeHide);
37806 menu.un("hide", onHide);
37807 menu.un("beforeshow", onBeforeShow);
37808 menu.un("show", onShow);
37809 var g = menu.group;
37810 if(g && menu.events["checkchange"]){
37811 groups[g].remove(menu);
37812 menu.un("checkchange", onCheck);
37817 registerCheckable : function(menuItem){
37818 var g = menuItem.group;
37823 groups[g].push(menuItem);
37824 menuItem.on("beforecheckchange", onBeforeCheck);
37829 unregisterCheckable : function(menuItem){
37830 var g = menuItem.group;
37832 groups[g].remove(menuItem);
37833 menuItem.un("beforecheckchange", onBeforeCheck);
37839 * Ext JS Library 1.1.1
37840 * Copyright(c) 2006-2007, Ext JS, LLC.
37842 * Originally Released Under LGPL - original licence link has changed is not relivant.
37845 * <script type="text/javascript">
37850 * @class Roo.menu.BaseItem
37851 * @extends Roo.Component
37852 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37853 * management and base configuration options shared by all menu components.
37855 * Creates a new BaseItem
37856 * @param {Object} config Configuration options
37858 Roo.menu.BaseItem = function(config){
37859 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37864 * Fires when this item is clicked
37865 * @param {Roo.menu.BaseItem} this
37866 * @param {Roo.EventObject} e
37871 * Fires when this item is activated
37872 * @param {Roo.menu.BaseItem} this
37876 * @event deactivate
37877 * Fires when this item is deactivated
37878 * @param {Roo.menu.BaseItem} this
37884 this.on("click", this.handler, this.scope, true);
37888 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37890 * @cfg {Function} handler
37891 * A function that will handle the click event of this menu item (defaults to undefined)
37894 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37896 canActivate : false,
37899 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37904 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37906 activeClass : "x-menu-item-active",
37908 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37910 hideOnClick : true,
37912 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37917 ctype: "Roo.menu.BaseItem",
37920 actionMode : "container",
37923 render : function(container, parentMenu){
37924 this.parentMenu = parentMenu;
37925 Roo.menu.BaseItem.superclass.render.call(this, container);
37926 this.container.menuItemId = this.id;
37930 onRender : function(container, position){
37931 this.el = Roo.get(this.el);
37932 container.dom.appendChild(this.el.dom);
37936 onClick : function(e){
37937 if(!this.disabled && this.fireEvent("click", this, e) !== false
37938 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37939 this.handleClick(e);
37946 activate : function(){
37950 var li = this.container;
37951 li.addClass(this.activeClass);
37952 this.region = li.getRegion().adjust(2, 2, -2, -2);
37953 this.fireEvent("activate", this);
37958 deactivate : function(){
37959 this.container.removeClass(this.activeClass);
37960 this.fireEvent("deactivate", this);
37964 shouldDeactivate : function(e){
37965 return !this.region || !this.region.contains(e.getPoint());
37969 handleClick : function(e){
37970 if(this.hideOnClick){
37971 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37976 expandMenu : function(autoActivate){
37981 hideMenu : function(){
37986 * Ext JS Library 1.1.1
37987 * Copyright(c) 2006-2007, Ext JS, LLC.
37989 * Originally Released Under LGPL - original licence link has changed is not relivant.
37992 * <script type="text/javascript">
37996 * @class Roo.menu.Adapter
37997 * @extends Roo.menu.BaseItem
37998 * 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.
37999 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38001 * Creates a new Adapter
38002 * @param {Object} config Configuration options
38004 Roo.menu.Adapter = function(component, config){
38005 Roo.menu.Adapter.superclass.constructor.call(this, config);
38006 this.component = component;
38008 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38010 canActivate : true,
38013 onRender : function(container, position){
38014 this.component.render(container);
38015 this.el = this.component.getEl();
38019 activate : function(){
38023 this.component.focus();
38024 this.fireEvent("activate", this);
38029 deactivate : function(){
38030 this.fireEvent("deactivate", this);
38034 disable : function(){
38035 this.component.disable();
38036 Roo.menu.Adapter.superclass.disable.call(this);
38040 enable : function(){
38041 this.component.enable();
38042 Roo.menu.Adapter.superclass.enable.call(this);
38046 * Ext JS Library 1.1.1
38047 * Copyright(c) 2006-2007, Ext JS, LLC.
38049 * Originally Released Under LGPL - original licence link has changed is not relivant.
38052 * <script type="text/javascript">
38056 * @class Roo.menu.TextItem
38057 * @extends Roo.menu.BaseItem
38058 * Adds a static text string to a menu, usually used as either a heading or group separator.
38059 * Note: old style constructor with text is still supported.
38062 * Creates a new TextItem
38063 * @param {Object} cfg Configuration
38065 Roo.menu.TextItem = function(cfg){
38066 if (typeof(cfg) == 'string') {
38069 Roo.apply(this,cfg);
38072 Roo.menu.TextItem.superclass.constructor.call(this);
38075 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38077 * @cfg {Boolean} text Text to show on item.
38082 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38084 hideOnClick : false,
38086 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38088 itemCls : "x-menu-text",
38091 onRender : function(){
38092 var s = document.createElement("span");
38093 s.className = this.itemCls;
38094 s.innerHTML = this.text;
38096 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38100 * Ext JS Library 1.1.1
38101 * Copyright(c) 2006-2007, Ext JS, LLC.
38103 * Originally Released Under LGPL - original licence link has changed is not relivant.
38106 * <script type="text/javascript">
38110 * @class Roo.menu.Separator
38111 * @extends Roo.menu.BaseItem
38112 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38113 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38115 * @param {Object} config Configuration options
38117 Roo.menu.Separator = function(config){
38118 Roo.menu.Separator.superclass.constructor.call(this, config);
38121 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38123 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38125 itemCls : "x-menu-sep",
38127 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38129 hideOnClick : false,
38132 onRender : function(li){
38133 var s = document.createElement("span");
38134 s.className = this.itemCls;
38135 s.innerHTML = " ";
38137 li.addClass("x-menu-sep-li");
38138 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38142 * Ext JS Library 1.1.1
38143 * Copyright(c) 2006-2007, Ext JS, LLC.
38145 * Originally Released Under LGPL - original licence link has changed is not relivant.
38148 * <script type="text/javascript">
38151 * @class Roo.menu.Item
38152 * @extends Roo.menu.BaseItem
38153 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38154 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38155 * activation and click handling.
38157 * Creates a new Item
38158 * @param {Object} config Configuration options
38160 Roo.menu.Item = function(config){
38161 Roo.menu.Item.superclass.constructor.call(this, config);
38163 this.menu = Roo.menu.MenuMgr.get(this.menu);
38166 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38169 * @cfg {String} text
38170 * The text to show on the menu item.
38174 * @cfg {String} HTML to render in menu
38175 * The text to show on the menu item (HTML version).
38179 * @cfg {String} icon
38180 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38184 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38186 itemCls : "x-menu-item",
38188 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38190 canActivate : true,
38192 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38195 // doc'd in BaseItem
38199 ctype: "Roo.menu.Item",
38202 onRender : function(container, position){
38203 var el = document.createElement("a");
38204 el.hideFocus = true;
38205 el.unselectable = "on";
38206 el.href = this.href || "#";
38207 if(this.hrefTarget){
38208 el.target = this.hrefTarget;
38210 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38212 var html = this.html.length ? this.html : String.format('{0}',this.text);
38214 el.innerHTML = String.format(
38215 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38216 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38218 Roo.menu.Item.superclass.onRender.call(this, container, position);
38222 * Sets the text to display in this menu item
38223 * @param {String} text The text to display
38224 * @param {Boolean} isHTML true to indicate text is pure html.
38226 setText : function(text, isHTML){
38234 var html = this.html.length ? this.html : String.format('{0}',this.text);
38236 this.el.update(String.format(
38237 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38238 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38239 this.parentMenu.autoWidth();
38244 handleClick : function(e){
38245 if(!this.href){ // if no link defined, stop the event automatically
38248 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38252 activate : function(autoExpand){
38253 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38263 shouldDeactivate : function(e){
38264 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38265 if(this.menu && this.menu.isVisible()){
38266 return !this.menu.getEl().getRegion().contains(e.getPoint());
38274 deactivate : function(){
38275 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38280 expandMenu : function(autoActivate){
38281 if(!this.disabled && this.menu){
38282 clearTimeout(this.hideTimer);
38283 delete this.hideTimer;
38284 if(!this.menu.isVisible() && !this.showTimer){
38285 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38286 }else if (this.menu.isVisible() && autoActivate){
38287 this.menu.tryActivate(0, 1);
38293 deferExpand : function(autoActivate){
38294 delete this.showTimer;
38295 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38297 this.menu.tryActivate(0, 1);
38302 hideMenu : function(){
38303 clearTimeout(this.showTimer);
38304 delete this.showTimer;
38305 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38306 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38311 deferHide : function(){
38312 delete this.hideTimer;
38317 * Ext JS Library 1.1.1
38318 * Copyright(c) 2006-2007, Ext JS, LLC.
38320 * Originally Released Under LGPL - original licence link has changed is not relivant.
38323 * <script type="text/javascript">
38327 * @class Roo.menu.CheckItem
38328 * @extends Roo.menu.Item
38329 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38331 * Creates a new CheckItem
38332 * @param {Object} config Configuration options
38334 Roo.menu.CheckItem = function(config){
38335 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38338 * @event beforecheckchange
38339 * Fires before the checked value is set, providing an opportunity to cancel if needed
38340 * @param {Roo.menu.CheckItem} this
38341 * @param {Boolean} checked The new checked value that will be set
38343 "beforecheckchange" : true,
38345 * @event checkchange
38346 * Fires after the checked value has been set
38347 * @param {Roo.menu.CheckItem} this
38348 * @param {Boolean} checked The checked value that was set
38350 "checkchange" : true
38352 if(this.checkHandler){
38353 this.on('checkchange', this.checkHandler, this.scope);
38356 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38358 * @cfg {String} group
38359 * All check items with the same group name will automatically be grouped into a single-select
38360 * radio button group (defaults to '')
38363 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38365 itemCls : "x-menu-item x-menu-check-item",
38367 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38369 groupClass : "x-menu-group-item",
38372 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38373 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38374 * initialized with checked = true will be rendered as checked.
38379 ctype: "Roo.menu.CheckItem",
38382 onRender : function(c){
38383 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38385 this.el.addClass(this.groupClass);
38387 Roo.menu.MenuMgr.registerCheckable(this);
38389 this.checked = false;
38390 this.setChecked(true, true);
38395 destroy : function(){
38397 Roo.menu.MenuMgr.unregisterCheckable(this);
38399 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38403 * Set the checked state of this item
38404 * @param {Boolean} checked The new checked value
38405 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38407 setChecked : function(state, suppressEvent){
38408 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38409 if(this.container){
38410 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38412 this.checked = state;
38413 if(suppressEvent !== true){
38414 this.fireEvent("checkchange", this, state);
38420 handleClick : function(e){
38421 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38422 this.setChecked(!this.checked);
38424 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38428 * Ext JS Library 1.1.1
38429 * Copyright(c) 2006-2007, Ext JS, LLC.
38431 * Originally Released Under LGPL - original licence link has changed is not relivant.
38434 * <script type="text/javascript">
38438 * @class Roo.menu.DateItem
38439 * @extends Roo.menu.Adapter
38440 * A menu item that wraps the {@link Roo.DatPicker} component.
38442 * Creates a new DateItem
38443 * @param {Object} config Configuration options
38445 Roo.menu.DateItem = function(config){
38446 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38447 /** The Roo.DatePicker object @type Roo.DatePicker */
38448 this.picker = this.component;
38449 this.addEvents({select: true});
38451 this.picker.on("render", function(picker){
38452 picker.getEl().swallowEvent("click");
38453 picker.container.addClass("x-menu-date-item");
38456 this.picker.on("select", this.onSelect, this);
38459 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38461 onSelect : function(picker, date){
38462 this.fireEvent("select", this, date, picker);
38463 Roo.menu.DateItem.superclass.handleClick.call(this);
38467 * Ext JS Library 1.1.1
38468 * Copyright(c) 2006-2007, Ext JS, LLC.
38470 * Originally Released Under LGPL - original licence link has changed is not relivant.
38473 * <script type="text/javascript">
38477 * @class Roo.menu.ColorItem
38478 * @extends Roo.menu.Adapter
38479 * A menu item that wraps the {@link Roo.ColorPalette} component.
38481 * Creates a new ColorItem
38482 * @param {Object} config Configuration options
38484 Roo.menu.ColorItem = function(config){
38485 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38486 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38487 this.palette = this.component;
38488 this.relayEvents(this.palette, ["select"]);
38489 if(this.selectHandler){
38490 this.on('select', this.selectHandler, this.scope);
38493 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38495 * Ext JS Library 1.1.1
38496 * Copyright(c) 2006-2007, Ext JS, LLC.
38498 * Originally Released Under LGPL - original licence link has changed is not relivant.
38501 * <script type="text/javascript">
38506 * @class Roo.menu.DateMenu
38507 * @extends Roo.menu.Menu
38508 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38510 * Creates a new DateMenu
38511 * @param {Object} config Configuration options
38513 Roo.menu.DateMenu = function(config){
38514 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38516 var di = new Roo.menu.DateItem(config);
38519 * The {@link Roo.DatePicker} instance for this DateMenu
38522 this.picker = di.picker;
38525 * @param {DatePicker} picker
38526 * @param {Date} date
38528 this.relayEvents(di, ["select"]);
38529 this.on('beforeshow', function(){
38531 this.picker.hideMonthPicker(false);
38535 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38539 * Ext JS Library 1.1.1
38540 * Copyright(c) 2006-2007, Ext JS, LLC.
38542 * Originally Released Under LGPL - original licence link has changed is not relivant.
38545 * <script type="text/javascript">
38550 * @class Roo.menu.ColorMenu
38551 * @extends Roo.menu.Menu
38552 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38554 * Creates a new ColorMenu
38555 * @param {Object} config Configuration options
38557 Roo.menu.ColorMenu = function(config){
38558 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38560 var ci = new Roo.menu.ColorItem(config);
38563 * The {@link Roo.ColorPalette} instance for this ColorMenu
38564 * @type ColorPalette
38566 this.palette = ci.palette;
38569 * @param {ColorPalette} palette
38570 * @param {String} color
38572 this.relayEvents(ci, ["select"]);
38574 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38576 * Ext JS Library 1.1.1
38577 * Copyright(c) 2006-2007, Ext JS, LLC.
38579 * Originally Released Under LGPL - original licence link has changed is not relivant.
38582 * <script type="text/javascript">
38586 * @class Roo.form.Field
38587 * @extends Roo.BoxComponent
38588 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38590 * Creates a new Field
38591 * @param {Object} config Configuration options
38593 Roo.form.Field = function(config){
38594 Roo.form.Field.superclass.constructor.call(this, config);
38597 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38599 * @cfg {String} fieldLabel Label to use when rendering a form.
38602 * @cfg {String} qtip Mouse over tip
38606 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38608 invalidClass : "x-form-invalid",
38610 * @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")
38612 invalidText : "The value in this field is invalid",
38614 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38616 focusClass : "x-form-focus",
38618 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38619 automatic validation (defaults to "keyup").
38621 validationEvent : "keyup",
38623 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38625 validateOnBlur : true,
38627 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38629 validationDelay : 250,
38631 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38632 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38634 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38636 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38638 fieldClass : "x-form-field",
38640 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38643 ----------- ----------------------------------------------------------------------
38644 qtip Display a quick tip when the user hovers over the field
38645 title Display a default browser title attribute popup
38646 under Add a block div beneath the field containing the error text
38647 side Add an error icon to the right of the field with a popup on hover
38648 [element id] Add the error text directly to the innerHTML of the specified element
38651 msgTarget : 'qtip',
38653 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38658 * @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.
38663 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38668 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38670 inputType : undefined,
38673 * @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).
38675 tabIndex : undefined,
38678 isFormField : true,
38683 * @property {Roo.Element} fieldEl
38684 * Element Containing the rendered Field (with label etc.)
38687 * @cfg {Mixed} value A value to initialize this field with.
38692 * @cfg {String} name The field's HTML name attribute.
38695 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38698 loadedValue : false,
38702 initComponent : function(){
38703 Roo.form.Field.superclass.initComponent.call(this);
38707 * Fires when this field receives input focus.
38708 * @param {Roo.form.Field} this
38713 * Fires when this field loses input focus.
38714 * @param {Roo.form.Field} this
38718 * @event specialkey
38719 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38720 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38721 * @param {Roo.form.Field} this
38722 * @param {Roo.EventObject} e The event object
38727 * Fires just before the field blurs if the field value has changed.
38728 * @param {Roo.form.Field} this
38729 * @param {Mixed} newValue The new value
38730 * @param {Mixed} oldValue The original value
38735 * Fires after the field has been marked as invalid.
38736 * @param {Roo.form.Field} this
38737 * @param {String} msg The validation message
38742 * Fires after the field has been validated with no errors.
38743 * @param {Roo.form.Field} this
38748 * Fires after the key up
38749 * @param {Roo.form.Field} this
38750 * @param {Roo.EventObject} e The event Object
38757 * Returns the name attribute of the field if available
38758 * @return {String} name The field name
38760 getName: function(){
38761 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38765 onRender : function(ct, position){
38766 Roo.form.Field.superclass.onRender.call(this, ct, position);
38768 var cfg = this.getAutoCreate();
38770 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38772 if (!cfg.name.length) {
38775 if(this.inputType){
38776 cfg.type = this.inputType;
38778 this.el = ct.createChild(cfg, position);
38780 var type = this.el.dom.type;
38782 if(type == 'password'){
38785 this.el.addClass('x-form-'+type);
38788 this.el.dom.readOnly = true;
38790 if(this.tabIndex !== undefined){
38791 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38794 this.el.addClass([this.fieldClass, this.cls]);
38799 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38800 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38801 * @return {Roo.form.Field} this
38803 applyTo : function(target){
38804 this.allowDomMove = false;
38805 this.el = Roo.get(target);
38806 this.render(this.el.dom.parentNode);
38811 initValue : function(){
38812 if(this.value !== undefined){
38813 this.setValue(this.value);
38814 }else if(this.el.dom.value.length > 0){
38815 this.setValue(this.el.dom.value);
38820 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38821 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38823 isDirty : function() {
38824 if(this.disabled) {
38827 return String(this.getValue()) !== String(this.originalValue);
38831 * stores the current value in loadedValue
38833 resetHasChanged : function()
38835 this.loadedValue = String(this.getValue());
38838 * checks the current value against the 'loaded' value.
38839 * Note - will return false if 'resetHasChanged' has not been called first.
38841 hasChanged : function()
38843 if(this.disabled || this.readOnly) {
38846 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38852 afterRender : function(){
38853 Roo.form.Field.superclass.afterRender.call(this);
38858 fireKey : function(e){
38859 //Roo.log('field ' + e.getKey());
38860 if(e.isNavKeyPress()){
38861 this.fireEvent("specialkey", this, e);
38866 * Resets the current field value to the originally loaded value and clears any validation messages
38868 reset : function(){
38869 this.setValue(this.resetValue);
38870 this.clearInvalid();
38874 initEvents : function(){
38875 // safari killled keypress - so keydown is now used..
38876 this.el.on("keydown" , this.fireKey, this);
38877 this.el.on("focus", this.onFocus, this);
38878 this.el.on("blur", this.onBlur, this);
38879 this.el.relayEvent('keyup', this);
38881 // reference to original value for reset
38882 this.originalValue = this.getValue();
38883 this.resetValue = this.getValue();
38887 onFocus : function(){
38888 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38889 this.el.addClass(this.focusClass);
38891 if(!this.hasFocus){
38892 this.hasFocus = true;
38893 this.startValue = this.getValue();
38894 this.fireEvent("focus", this);
38898 beforeBlur : Roo.emptyFn,
38901 onBlur : function(){
38903 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38904 this.el.removeClass(this.focusClass);
38906 this.hasFocus = false;
38907 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38910 var v = this.getValue();
38911 if(String(v) !== String(this.startValue)){
38912 this.fireEvent('change', this, v, this.startValue);
38914 this.fireEvent("blur", this);
38918 * Returns whether or not the field value is currently valid
38919 * @param {Boolean} preventMark True to disable marking the field invalid
38920 * @return {Boolean} True if the value is valid, else false
38922 isValid : function(preventMark){
38926 var restore = this.preventMark;
38927 this.preventMark = preventMark === true;
38928 var v = this.validateValue(this.processValue(this.getRawValue()));
38929 this.preventMark = restore;
38934 * Validates the field value
38935 * @return {Boolean} True if the value is valid, else false
38937 validate : function(){
38938 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38939 this.clearInvalid();
38945 processValue : function(value){
38950 // Subclasses should provide the validation implementation by overriding this
38951 validateValue : function(value){
38956 * Mark this field as invalid
38957 * @param {String} msg The validation message
38959 markInvalid : function(msg){
38960 if(!this.rendered || this.preventMark){ // not rendered
38964 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38966 obj.el.addClass(this.invalidClass);
38967 msg = msg || this.invalidText;
38968 switch(this.msgTarget){
38970 obj.el.dom.qtip = msg;
38971 obj.el.dom.qclass = 'x-form-invalid-tip';
38972 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38973 Roo.QuickTips.enable();
38977 this.el.dom.title = msg;
38981 var elp = this.el.findParent('.x-form-element', 5, true);
38982 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38983 this.errorEl.setWidth(elp.getWidth(true)-20);
38985 this.errorEl.update(msg);
38986 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38989 if(!this.errorIcon){
38990 var elp = this.el.findParent('.x-form-element', 5, true);
38991 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38993 this.alignErrorIcon();
38994 this.errorIcon.dom.qtip = msg;
38995 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38996 this.errorIcon.show();
38997 this.on('resize', this.alignErrorIcon, this);
39000 var t = Roo.getDom(this.msgTarget);
39002 t.style.display = this.msgDisplay;
39005 this.fireEvent('invalid', this, msg);
39009 alignErrorIcon : function(){
39010 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39014 * Clear any invalid styles/messages for this field
39016 clearInvalid : function(){
39017 if(!this.rendered || this.preventMark){ // not rendered
39020 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39022 obj.el.removeClass(this.invalidClass);
39023 switch(this.msgTarget){
39025 obj.el.dom.qtip = '';
39028 this.el.dom.title = '';
39032 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39036 if(this.errorIcon){
39037 this.errorIcon.dom.qtip = '';
39038 this.errorIcon.hide();
39039 this.un('resize', this.alignErrorIcon, this);
39043 var t = Roo.getDom(this.msgTarget);
39045 t.style.display = 'none';
39048 this.fireEvent('valid', this);
39052 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39053 * @return {Mixed} value The field value
39055 getRawValue : function(){
39056 var v = this.el.getValue();
39062 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39063 * @return {Mixed} value The field value
39065 getValue : function(){
39066 var v = this.el.getValue();
39072 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39073 * @param {Mixed} value The value to set
39075 setRawValue : function(v){
39076 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39080 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39081 * @param {Mixed} value The value to set
39083 setValue : function(v){
39086 this.el.dom.value = (v === null || v === undefined ? '' : v);
39091 adjustSize : function(w, h){
39092 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39093 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39097 adjustWidth : function(tag, w){
39098 tag = tag.toLowerCase();
39099 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39100 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39101 if(tag == 'input'){
39104 if(tag == 'textarea'){
39107 }else if(Roo.isOpera){
39108 if(tag == 'input'){
39111 if(tag == 'textarea'){
39121 // anything other than normal should be considered experimental
39122 Roo.form.Field.msgFx = {
39124 show: function(msgEl, f){
39125 msgEl.setDisplayed('block');
39128 hide : function(msgEl, f){
39129 msgEl.setDisplayed(false).update('');
39134 show: function(msgEl, f){
39135 msgEl.slideIn('t', {stopFx:true});
39138 hide : function(msgEl, f){
39139 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39144 show: function(msgEl, f){
39145 msgEl.fixDisplay();
39146 msgEl.alignTo(f.el, 'tl-tr');
39147 msgEl.slideIn('l', {stopFx:true});
39150 hide : function(msgEl, f){
39151 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39156 * Ext JS Library 1.1.1
39157 * Copyright(c) 2006-2007, Ext JS, LLC.
39159 * Originally Released Under LGPL - original licence link has changed is not relivant.
39162 * <script type="text/javascript">
39167 * @class Roo.form.TextField
39168 * @extends Roo.form.Field
39169 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39170 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39172 * Creates a new TextField
39173 * @param {Object} config Configuration options
39175 Roo.form.TextField = function(config){
39176 Roo.form.TextField.superclass.constructor.call(this, config);
39180 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39181 * according to the default logic, but this event provides a hook for the developer to apply additional
39182 * logic at runtime to resize the field if needed.
39183 * @param {Roo.form.Field} this This text field
39184 * @param {Number} width The new field width
39190 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39192 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39196 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39200 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39204 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39208 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39212 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39214 disableKeyFilter : false,
39216 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39220 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39224 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39226 maxLength : Number.MAX_VALUE,
39228 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39230 minLengthText : "The minimum length for this field is {0}",
39232 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39234 maxLengthText : "The maximum length for this field is {0}",
39236 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39238 selectOnFocus : false,
39240 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39242 blankText : "This field is required",
39244 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39245 * If available, this function will be called only after the basic validators all return true, and will be passed the
39246 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39250 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39251 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39252 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39256 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39260 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39266 initEvents : function()
39268 if (this.emptyText) {
39269 this.el.attr('placeholder', this.emptyText);
39272 Roo.form.TextField.superclass.initEvents.call(this);
39273 if(this.validationEvent == 'keyup'){
39274 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39275 this.el.on('keyup', this.filterValidation, this);
39277 else if(this.validationEvent !== false){
39278 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39281 if(this.selectOnFocus){
39282 this.on("focus", this.preFocus, this);
39285 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39286 this.el.on("keypress", this.filterKeys, this);
39289 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39290 this.el.on("click", this.autoSize, this);
39292 if(this.el.is('input[type=password]') && Roo.isSafari){
39293 this.el.on('keydown', this.SafariOnKeyDown, this);
39297 processValue : function(value){
39298 if(this.stripCharsRe){
39299 var newValue = value.replace(this.stripCharsRe, '');
39300 if(newValue !== value){
39301 this.setRawValue(newValue);
39308 filterValidation : function(e){
39309 if(!e.isNavKeyPress()){
39310 this.validationTask.delay(this.validationDelay);
39315 onKeyUp : function(e){
39316 if(!e.isNavKeyPress()){
39322 * Resets the current field value to the originally-loaded value and clears any validation messages.
39325 reset : function(){
39326 Roo.form.TextField.superclass.reset.call(this);
39332 preFocus : function(){
39334 if(this.selectOnFocus){
39335 this.el.dom.select();
39341 filterKeys : function(e){
39342 var k = e.getKey();
39343 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39346 var c = e.getCharCode(), cc = String.fromCharCode(c);
39347 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39350 if(!this.maskRe.test(cc)){
39355 setValue : function(v){
39357 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39363 * Validates a value according to the field's validation rules and marks the field as invalid
39364 * if the validation fails
39365 * @param {Mixed} value The value to validate
39366 * @return {Boolean} True if the value is valid, else false
39368 validateValue : function(value){
39369 if(value.length < 1) { // if it's blank
39370 if(this.allowBlank){
39371 this.clearInvalid();
39374 this.markInvalid(this.blankText);
39378 if(value.length < this.minLength){
39379 this.markInvalid(String.format(this.minLengthText, this.minLength));
39382 if(value.length > this.maxLength){
39383 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39387 var vt = Roo.form.VTypes;
39388 if(!vt[this.vtype](value, this)){
39389 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39393 if(typeof this.validator == "function"){
39394 var msg = this.validator(value);
39396 this.markInvalid(msg);
39400 if(this.regex && !this.regex.test(value)){
39401 this.markInvalid(this.regexText);
39408 * Selects text in this field
39409 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39410 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39412 selectText : function(start, end){
39413 var v = this.getRawValue();
39415 start = start === undefined ? 0 : start;
39416 end = end === undefined ? v.length : end;
39417 var d = this.el.dom;
39418 if(d.setSelectionRange){
39419 d.setSelectionRange(start, end);
39420 }else if(d.createTextRange){
39421 var range = d.createTextRange();
39422 range.moveStart("character", start);
39423 range.moveEnd("character", v.length-end);
39430 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39431 * This only takes effect if grow = true, and fires the autosize event.
39433 autoSize : function(){
39434 if(!this.grow || !this.rendered){
39438 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39441 var v = el.dom.value;
39442 var d = document.createElement('div');
39443 d.appendChild(document.createTextNode(v));
39447 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39448 this.el.setWidth(w);
39449 this.fireEvent("autosize", this, w);
39453 SafariOnKeyDown : function(event)
39455 // this is a workaround for a password hang bug on chrome/ webkit.
39457 var isSelectAll = false;
39459 if(this.el.dom.selectionEnd > 0){
39460 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39462 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39463 event.preventDefault();
39468 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39470 event.preventDefault();
39471 // this is very hacky as keydown always get's upper case.
39473 var cc = String.fromCharCode(event.getCharCode());
39476 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39484 * Ext JS Library 1.1.1
39485 * Copyright(c) 2006-2007, Ext JS, LLC.
39487 * Originally Released Under LGPL - original licence link has changed is not relivant.
39490 * <script type="text/javascript">
39494 * @class Roo.form.Hidden
39495 * @extends Roo.form.TextField
39496 * Simple Hidden element used on forms
39498 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39501 * Creates a new Hidden form element.
39502 * @param {Object} config Configuration options
39507 // easy hidden field...
39508 Roo.form.Hidden = function(config){
39509 Roo.form.Hidden.superclass.constructor.call(this, config);
39512 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39514 inputType: 'hidden',
39517 labelSeparator: '',
39519 itemCls : 'x-form-item-display-none'
39527 * Ext JS Library 1.1.1
39528 * Copyright(c) 2006-2007, Ext JS, LLC.
39530 * Originally Released Under LGPL - original licence link has changed is not relivant.
39533 * <script type="text/javascript">
39537 * @class Roo.form.TriggerField
39538 * @extends Roo.form.TextField
39539 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39540 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39541 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39542 * for which you can provide a custom implementation. For example:
39544 var trigger = new Roo.form.TriggerField();
39545 trigger.onTriggerClick = myTriggerFn;
39546 trigger.applyTo('my-field');
39549 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39550 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39551 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39552 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39554 * Create a new TriggerField.
39555 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39556 * to the base TextField)
39558 Roo.form.TriggerField = function(config){
39559 this.mimicing = false;
39560 Roo.form.TriggerField.superclass.constructor.call(this, config);
39563 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39565 * @cfg {String} triggerClass A CSS class to apply to the trigger
39568 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39569 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39571 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39573 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39577 /** @cfg {Boolean} grow @hide */
39578 /** @cfg {Number} growMin @hide */
39579 /** @cfg {Number} growMax @hide */
39585 autoSize: Roo.emptyFn,
39589 deferHeight : true,
39592 actionMode : 'wrap',
39594 onResize : function(w, h){
39595 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39596 if(typeof w == 'number'){
39597 var x = w - this.trigger.getWidth();
39598 this.el.setWidth(this.adjustWidth('input', x));
39599 this.trigger.setStyle('left', x+'px');
39604 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39607 getResizeEl : function(){
39612 getPositionEl : function(){
39617 alignErrorIcon : function(){
39618 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39622 onRender : function(ct, position){
39623 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39624 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39625 this.trigger = this.wrap.createChild(this.triggerConfig ||
39626 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39627 if(this.hideTrigger){
39628 this.trigger.setDisplayed(false);
39630 this.initTrigger();
39632 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39637 initTrigger : function(){
39638 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39639 this.trigger.addClassOnOver('x-form-trigger-over');
39640 this.trigger.addClassOnClick('x-form-trigger-click');
39644 onDestroy : function(){
39646 this.trigger.removeAllListeners();
39647 this.trigger.remove();
39650 this.wrap.remove();
39652 Roo.form.TriggerField.superclass.onDestroy.call(this);
39656 onFocus : function(){
39657 Roo.form.TriggerField.superclass.onFocus.call(this);
39658 if(!this.mimicing){
39659 this.wrap.addClass('x-trigger-wrap-focus');
39660 this.mimicing = true;
39661 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39662 if(this.monitorTab){
39663 this.el.on("keydown", this.checkTab, this);
39669 checkTab : function(e){
39670 if(e.getKey() == e.TAB){
39671 this.triggerBlur();
39676 onBlur : function(){
39681 mimicBlur : function(e, t){
39682 if(!this.wrap.contains(t) && this.validateBlur()){
39683 this.triggerBlur();
39688 triggerBlur : function(){
39689 this.mimicing = false;
39690 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39691 if(this.monitorTab){
39692 this.el.un("keydown", this.checkTab, this);
39694 this.wrap.removeClass('x-trigger-wrap-focus');
39695 Roo.form.TriggerField.superclass.onBlur.call(this);
39699 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39700 validateBlur : function(e, t){
39705 onDisable : function(){
39706 Roo.form.TriggerField.superclass.onDisable.call(this);
39708 this.wrap.addClass('x-item-disabled');
39713 onEnable : function(){
39714 Roo.form.TriggerField.superclass.onEnable.call(this);
39716 this.wrap.removeClass('x-item-disabled');
39721 onShow : function(){
39722 var ae = this.getActionEl();
39725 ae.dom.style.display = '';
39726 ae.dom.style.visibility = 'visible';
39732 onHide : function(){
39733 var ae = this.getActionEl();
39734 ae.dom.style.display = 'none';
39738 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39739 * by an implementing function.
39741 * @param {EventObject} e
39743 onTriggerClick : Roo.emptyFn
39746 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39747 // to be extended by an implementing class. For an example of implementing this class, see the custom
39748 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39749 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39750 initComponent : function(){
39751 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39753 this.triggerConfig = {
39754 tag:'span', cls:'x-form-twin-triggers', cn:[
39755 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39756 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39760 getTrigger : function(index){
39761 return this.triggers[index];
39764 initTrigger : function(){
39765 var ts = this.trigger.select('.x-form-trigger', true);
39766 this.wrap.setStyle('overflow', 'hidden');
39767 var triggerField = this;
39768 ts.each(function(t, all, index){
39769 t.hide = function(){
39770 var w = triggerField.wrap.getWidth();
39771 this.dom.style.display = 'none';
39772 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39774 t.show = function(){
39775 var w = triggerField.wrap.getWidth();
39776 this.dom.style.display = '';
39777 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39779 var triggerIndex = 'Trigger'+(index+1);
39781 if(this['hide'+triggerIndex]){
39782 t.dom.style.display = 'none';
39784 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39785 t.addClassOnOver('x-form-trigger-over');
39786 t.addClassOnClick('x-form-trigger-click');
39788 this.triggers = ts.elements;
39791 onTrigger1Click : Roo.emptyFn,
39792 onTrigger2Click : Roo.emptyFn
39795 * Ext JS Library 1.1.1
39796 * Copyright(c) 2006-2007, Ext JS, LLC.
39798 * Originally Released Under LGPL - original licence link has changed is not relivant.
39801 * <script type="text/javascript">
39805 * @class Roo.form.TextArea
39806 * @extends Roo.form.TextField
39807 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39808 * support for auto-sizing.
39810 * Creates a new TextArea
39811 * @param {Object} config Configuration options
39813 Roo.form.TextArea = function(config){
39814 Roo.form.TextArea.superclass.constructor.call(this, config);
39815 // these are provided exchanges for backwards compat
39816 // minHeight/maxHeight were replaced by growMin/growMax to be
39817 // compatible with TextField growing config values
39818 if(this.minHeight !== undefined){
39819 this.growMin = this.minHeight;
39821 if(this.maxHeight !== undefined){
39822 this.growMax = this.maxHeight;
39826 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39828 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39832 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39836 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39837 * in the field (equivalent to setting overflow: hidden, defaults to false)
39839 preventScrollbars: false,
39841 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39842 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39846 onRender : function(ct, position){
39848 this.defaultAutoCreate = {
39850 style:"width:300px;height:60px;",
39851 autocomplete: "new-password"
39854 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39856 this.textSizeEl = Roo.DomHelper.append(document.body, {
39857 tag: "pre", cls: "x-form-grow-sizer"
39859 if(this.preventScrollbars){
39860 this.el.setStyle("overflow", "hidden");
39862 this.el.setHeight(this.growMin);
39866 onDestroy : function(){
39867 if(this.textSizeEl){
39868 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39870 Roo.form.TextArea.superclass.onDestroy.call(this);
39874 onKeyUp : function(e){
39875 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39881 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39882 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39884 autoSize : function(){
39885 if(!this.grow || !this.textSizeEl){
39889 var v = el.dom.value;
39890 var ts = this.textSizeEl;
39893 ts.appendChild(document.createTextNode(v));
39896 Roo.fly(ts).setWidth(this.el.getWidth());
39898 v = "  ";
39901 v = v.replace(/\n/g, '<p> </p>');
39903 v += " \n ";
39906 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39907 if(h != this.lastHeight){
39908 this.lastHeight = h;
39909 this.el.setHeight(h);
39910 this.fireEvent("autosize", this, h);
39915 * Ext JS Library 1.1.1
39916 * Copyright(c) 2006-2007, Ext JS, LLC.
39918 * Originally Released Under LGPL - original licence link has changed is not relivant.
39921 * <script type="text/javascript">
39926 * @class Roo.form.NumberField
39927 * @extends Roo.form.TextField
39928 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39930 * Creates a new NumberField
39931 * @param {Object} config Configuration options
39933 Roo.form.NumberField = function(config){
39934 Roo.form.NumberField.superclass.constructor.call(this, config);
39937 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39939 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39941 fieldClass: "x-form-field x-form-num-field",
39943 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39945 allowDecimals : true,
39947 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39949 decimalSeparator : ".",
39951 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39953 decimalPrecision : 2,
39955 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39957 allowNegative : true,
39959 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39961 minValue : Number.NEGATIVE_INFINITY,
39963 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39965 maxValue : Number.MAX_VALUE,
39967 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39969 minText : "The minimum value for this field is {0}",
39971 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39973 maxText : "The maximum value for this field is {0}",
39975 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39976 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39978 nanText : "{0} is not a valid number",
39981 initEvents : function(){
39982 Roo.form.NumberField.superclass.initEvents.call(this);
39983 var allowed = "0123456789";
39984 if(this.allowDecimals){
39985 allowed += this.decimalSeparator;
39987 if(this.allowNegative){
39990 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39991 var keyPress = function(e){
39992 var k = e.getKey();
39993 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39996 var c = e.getCharCode();
39997 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40001 this.el.on("keypress", keyPress, this);
40005 validateValue : function(value){
40006 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40009 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40012 var num = this.parseValue(value);
40014 this.markInvalid(String.format(this.nanText, value));
40017 if(num < this.minValue){
40018 this.markInvalid(String.format(this.minText, this.minValue));
40021 if(num > this.maxValue){
40022 this.markInvalid(String.format(this.maxText, this.maxValue));
40028 getValue : function(){
40029 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40033 parseValue : function(value){
40034 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40035 return isNaN(value) ? '' : value;
40039 fixPrecision : function(value){
40040 var nan = isNaN(value);
40041 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40042 return nan ? '' : value;
40044 return parseFloat(value).toFixed(this.decimalPrecision);
40047 setValue : function(v){
40048 v = this.fixPrecision(v);
40049 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40053 decimalPrecisionFcn : function(v){
40054 return Math.floor(v);
40057 beforeBlur : function(){
40058 var v = this.parseValue(this.getRawValue());
40065 * Ext JS Library 1.1.1
40066 * Copyright(c) 2006-2007, Ext JS, LLC.
40068 * Originally Released Under LGPL - original licence link has changed is not relivant.
40071 * <script type="text/javascript">
40075 * @class Roo.form.DateField
40076 * @extends Roo.form.TriggerField
40077 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40079 * Create a new DateField
40080 * @param {Object} config
40082 Roo.form.DateField = function(config){
40083 Roo.form.DateField.superclass.constructor.call(this, config);
40089 * Fires when a date is selected
40090 * @param {Roo.form.DateField} combo This combo box
40091 * @param {Date} date The date selected
40098 if(typeof this.minValue == "string") {
40099 this.minValue = this.parseDate(this.minValue);
40101 if(typeof this.maxValue == "string") {
40102 this.maxValue = this.parseDate(this.maxValue);
40104 this.ddMatch = null;
40105 if(this.disabledDates){
40106 var dd = this.disabledDates;
40108 for(var i = 0; i < dd.length; i++){
40110 if(i != dd.length-1) {
40114 this.ddMatch = new RegExp(re + ")");
40118 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40120 * @cfg {String} format
40121 * The default date format string which can be overriden for localization support. The format must be
40122 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40126 * @cfg {String} altFormats
40127 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40128 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40130 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40132 * @cfg {Array} disabledDays
40133 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40135 disabledDays : null,
40137 * @cfg {String} disabledDaysText
40138 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40140 disabledDaysText : "Disabled",
40142 * @cfg {Array} disabledDates
40143 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40144 * expression so they are very powerful. Some examples:
40146 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40147 * <li>["03/08", "09/16"] would disable those days for every year</li>
40148 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40149 * <li>["03/../2006"] would disable every day in March 2006</li>
40150 * <li>["^03"] would disable every day in every March</li>
40152 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40153 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40155 disabledDates : null,
40157 * @cfg {String} disabledDatesText
40158 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40160 disabledDatesText : "Disabled",
40162 * @cfg {Date/String} minValue
40163 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40164 * valid format (defaults to null).
40168 * @cfg {Date/String} maxValue
40169 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40170 * valid format (defaults to null).
40174 * @cfg {String} minText
40175 * The error text to display when the date in the cell is before minValue (defaults to
40176 * 'The date in this field must be after {minValue}').
40178 minText : "The date in this field must be equal to or after {0}",
40180 * @cfg {String} maxText
40181 * The error text to display when the date in the cell is after maxValue (defaults to
40182 * 'The date in this field must be before {maxValue}').
40184 maxText : "The date in this field must be equal to or before {0}",
40186 * @cfg {String} invalidText
40187 * The error text to display when the date in the field is invalid (defaults to
40188 * '{value} is not a valid date - it must be in the format {format}').
40190 invalidText : "{0} is not a valid date - it must be in the format {1}",
40192 * @cfg {String} triggerClass
40193 * An additional CSS class used to style the trigger button. The trigger will always get the
40194 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40195 * which displays a calendar icon).
40197 triggerClass : 'x-form-date-trigger',
40201 * @cfg {Boolean} useIso
40202 * if enabled, then the date field will use a hidden field to store the
40203 * real value as iso formated date. default (false)
40207 * @cfg {String/Object} autoCreate
40208 * A DomHelper element spec, or true for a default element spec (defaults to
40209 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40212 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40215 hiddenField: false,
40217 onRender : function(ct, position)
40219 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40221 //this.el.dom.removeAttribute('name');
40222 Roo.log("Changing name?");
40223 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40224 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40226 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40227 // prevent input submission
40228 this.hiddenName = this.name;
40235 validateValue : function(value)
40237 value = this.formatDate(value);
40238 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40239 Roo.log('super failed');
40242 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40245 var svalue = value;
40246 value = this.parseDate(value);
40248 Roo.log('parse date failed' + svalue);
40249 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40252 var time = value.getTime();
40253 if(this.minValue && time < this.minValue.getTime()){
40254 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40257 if(this.maxValue && time > this.maxValue.getTime()){
40258 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40261 if(this.disabledDays){
40262 var day = value.getDay();
40263 for(var i = 0; i < this.disabledDays.length; i++) {
40264 if(day === this.disabledDays[i]){
40265 this.markInvalid(this.disabledDaysText);
40270 var fvalue = this.formatDate(value);
40271 if(this.ddMatch && this.ddMatch.test(fvalue)){
40272 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40279 // Provides logic to override the default TriggerField.validateBlur which just returns true
40280 validateBlur : function(){
40281 return !this.menu || !this.menu.isVisible();
40284 getName: function()
40286 // returns hidden if it's set..
40287 if (!this.rendered) {return ''};
40288 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40293 * Returns the current date value of the date field.
40294 * @return {Date} The date value
40296 getValue : function(){
40298 return this.hiddenField ?
40299 this.hiddenField.value :
40300 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40304 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40305 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40306 * (the default format used is "m/d/y").
40309 //All of these calls set the same date value (May 4, 2006)
40311 //Pass a date object:
40312 var dt = new Date('5/4/06');
40313 dateField.setValue(dt);
40315 //Pass a date string (default format):
40316 dateField.setValue('5/4/06');
40318 //Pass a date string (custom format):
40319 dateField.format = 'Y-m-d';
40320 dateField.setValue('2006-5-4');
40322 * @param {String/Date} date The date or valid date string
40324 setValue : function(date){
40325 if (this.hiddenField) {
40326 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40328 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40329 // make sure the value field is always stored as a date..
40330 this.value = this.parseDate(date);
40336 parseDate : function(value){
40337 if(!value || value instanceof Date){
40340 var v = Date.parseDate(value, this.format);
40341 if (!v && this.useIso) {
40342 v = Date.parseDate(value, 'Y-m-d');
40344 if(!v && this.altFormats){
40345 if(!this.altFormatsArray){
40346 this.altFormatsArray = this.altFormats.split("|");
40348 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40349 v = Date.parseDate(value, this.altFormatsArray[i]);
40356 formatDate : function(date, fmt){
40357 return (!date || !(date instanceof Date)) ?
40358 date : date.dateFormat(fmt || this.format);
40363 select: function(m, d){
40366 this.fireEvent('select', this, d);
40368 show : function(){ // retain focus styling
40372 this.focus.defer(10, this);
40373 var ml = this.menuListeners;
40374 this.menu.un("select", ml.select, this);
40375 this.menu.un("show", ml.show, this);
40376 this.menu.un("hide", ml.hide, this);
40381 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40382 onTriggerClick : function(){
40386 if(this.menu == null){
40387 this.menu = new Roo.menu.DateMenu();
40389 Roo.apply(this.menu.picker, {
40390 showClear: this.allowBlank,
40391 minDate : this.minValue,
40392 maxDate : this.maxValue,
40393 disabledDatesRE : this.ddMatch,
40394 disabledDatesText : this.disabledDatesText,
40395 disabledDays : this.disabledDays,
40396 disabledDaysText : this.disabledDaysText,
40397 format : this.useIso ? 'Y-m-d' : this.format,
40398 minText : String.format(this.minText, this.formatDate(this.minValue)),
40399 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40401 this.menu.on(Roo.apply({}, this.menuListeners, {
40404 this.menu.picker.setValue(this.getValue() || new Date());
40405 this.menu.show(this.el, "tl-bl?");
40408 beforeBlur : function(){
40409 var v = this.parseDate(this.getRawValue());
40419 isDirty : function() {
40420 if(this.disabled) {
40424 if(typeof(this.startValue) === 'undefined'){
40428 return String(this.getValue()) !== String(this.startValue);
40433 * Ext JS Library 1.1.1
40434 * Copyright(c) 2006-2007, Ext JS, LLC.
40436 * Originally Released Under LGPL - original licence link has changed is not relivant.
40439 * <script type="text/javascript">
40443 * @class Roo.form.MonthField
40444 * @extends Roo.form.TriggerField
40445 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40447 * Create a new MonthField
40448 * @param {Object} config
40450 Roo.form.MonthField = function(config){
40452 Roo.form.MonthField.superclass.constructor.call(this, config);
40458 * Fires when a date is selected
40459 * @param {Roo.form.MonthFieeld} combo This combo box
40460 * @param {Date} date The date selected
40467 if(typeof this.minValue == "string") {
40468 this.minValue = this.parseDate(this.minValue);
40470 if(typeof this.maxValue == "string") {
40471 this.maxValue = this.parseDate(this.maxValue);
40473 this.ddMatch = null;
40474 if(this.disabledDates){
40475 var dd = this.disabledDates;
40477 for(var i = 0; i < dd.length; i++){
40479 if(i != dd.length-1) {
40483 this.ddMatch = new RegExp(re + ")");
40487 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40489 * @cfg {String} format
40490 * The default date format string which can be overriden for localization support. The format must be
40491 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40495 * @cfg {String} altFormats
40496 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40497 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40499 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40501 * @cfg {Array} disabledDays
40502 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40504 disabledDays : [0,1,2,3,4,5,6],
40506 * @cfg {String} disabledDaysText
40507 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40509 disabledDaysText : "Disabled",
40511 * @cfg {Array} disabledDates
40512 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40513 * expression so they are very powerful. Some examples:
40515 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40516 * <li>["03/08", "09/16"] would disable those days for every year</li>
40517 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40518 * <li>["03/../2006"] would disable every day in March 2006</li>
40519 * <li>["^03"] would disable every day in every March</li>
40521 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40522 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40524 disabledDates : null,
40526 * @cfg {String} disabledDatesText
40527 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40529 disabledDatesText : "Disabled",
40531 * @cfg {Date/String} minValue
40532 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40533 * valid format (defaults to null).
40537 * @cfg {Date/String} maxValue
40538 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40539 * valid format (defaults to null).
40543 * @cfg {String} minText
40544 * The error text to display when the date in the cell is before minValue (defaults to
40545 * 'The date in this field must be after {minValue}').
40547 minText : "The date in this field must be equal to or after {0}",
40549 * @cfg {String} maxTextf
40550 * The error text to display when the date in the cell is after maxValue (defaults to
40551 * 'The date in this field must be before {maxValue}').
40553 maxText : "The date in this field must be equal to or before {0}",
40555 * @cfg {String} invalidText
40556 * The error text to display when the date in the field is invalid (defaults to
40557 * '{value} is not a valid date - it must be in the format {format}').
40559 invalidText : "{0} is not a valid date - it must be in the format {1}",
40561 * @cfg {String} triggerClass
40562 * An additional CSS class used to style the trigger button. The trigger will always get the
40563 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40564 * which displays a calendar icon).
40566 triggerClass : 'x-form-date-trigger',
40570 * @cfg {Boolean} useIso
40571 * if enabled, then the date field will use a hidden field to store the
40572 * real value as iso formated date. default (true)
40576 * @cfg {String/Object} autoCreate
40577 * A DomHelper element spec, or true for a default element spec (defaults to
40578 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40581 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40584 hiddenField: false,
40586 hideMonthPicker : false,
40588 onRender : function(ct, position)
40590 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40592 this.el.dom.removeAttribute('name');
40593 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40595 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40596 // prevent input submission
40597 this.hiddenName = this.name;
40604 validateValue : function(value)
40606 value = this.formatDate(value);
40607 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40610 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40613 var svalue = value;
40614 value = this.parseDate(value);
40616 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40619 var time = value.getTime();
40620 if(this.minValue && time < this.minValue.getTime()){
40621 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40624 if(this.maxValue && time > this.maxValue.getTime()){
40625 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40628 /*if(this.disabledDays){
40629 var day = value.getDay();
40630 for(var i = 0; i < this.disabledDays.length; i++) {
40631 if(day === this.disabledDays[i]){
40632 this.markInvalid(this.disabledDaysText);
40638 var fvalue = this.formatDate(value);
40639 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40640 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40648 // Provides logic to override the default TriggerField.validateBlur which just returns true
40649 validateBlur : function(){
40650 return !this.menu || !this.menu.isVisible();
40654 * Returns the current date value of the date field.
40655 * @return {Date} The date value
40657 getValue : function(){
40661 return this.hiddenField ?
40662 this.hiddenField.value :
40663 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40667 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40668 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40669 * (the default format used is "m/d/y").
40672 //All of these calls set the same date value (May 4, 2006)
40674 //Pass a date object:
40675 var dt = new Date('5/4/06');
40676 monthField.setValue(dt);
40678 //Pass a date string (default format):
40679 monthField.setValue('5/4/06');
40681 //Pass a date string (custom format):
40682 monthField.format = 'Y-m-d';
40683 monthField.setValue('2006-5-4');
40685 * @param {String/Date} date The date or valid date string
40687 setValue : function(date){
40688 Roo.log('month setValue' + date);
40689 // can only be first of month..
40691 var val = this.parseDate(date);
40693 if (this.hiddenField) {
40694 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40696 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40697 this.value = this.parseDate(date);
40701 parseDate : function(value){
40702 if(!value || value instanceof Date){
40703 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40706 var v = Date.parseDate(value, this.format);
40707 if (!v && this.useIso) {
40708 v = Date.parseDate(value, 'Y-m-d');
40712 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40716 if(!v && this.altFormats){
40717 if(!this.altFormatsArray){
40718 this.altFormatsArray = this.altFormats.split("|");
40720 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40721 v = Date.parseDate(value, this.altFormatsArray[i]);
40728 formatDate : function(date, fmt){
40729 return (!date || !(date instanceof Date)) ?
40730 date : date.dateFormat(fmt || this.format);
40735 select: function(m, d){
40737 this.fireEvent('select', this, d);
40739 show : function(){ // retain focus styling
40743 this.focus.defer(10, this);
40744 var ml = this.menuListeners;
40745 this.menu.un("select", ml.select, this);
40746 this.menu.un("show", ml.show, this);
40747 this.menu.un("hide", ml.hide, this);
40751 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40752 onTriggerClick : function(){
40756 if(this.menu == null){
40757 this.menu = new Roo.menu.DateMenu();
40761 Roo.apply(this.menu.picker, {
40763 showClear: this.allowBlank,
40764 minDate : this.minValue,
40765 maxDate : this.maxValue,
40766 disabledDatesRE : this.ddMatch,
40767 disabledDatesText : this.disabledDatesText,
40769 format : this.useIso ? 'Y-m-d' : this.format,
40770 minText : String.format(this.minText, this.formatDate(this.minValue)),
40771 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40774 this.menu.on(Roo.apply({}, this.menuListeners, {
40782 // hide month picker get's called when we called by 'before hide';
40784 var ignorehide = true;
40785 p.hideMonthPicker = function(disableAnim){
40789 if(this.monthPicker){
40790 Roo.log("hideMonthPicker called");
40791 if(disableAnim === true){
40792 this.monthPicker.hide();
40794 this.monthPicker.slideOut('t', {duration:.2});
40795 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40796 p.fireEvent("select", this, this.value);
40802 Roo.log('picker set value');
40803 Roo.log(this.getValue());
40804 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40805 m.show(this.el, 'tl-bl?');
40806 ignorehide = false;
40807 // this will trigger hideMonthPicker..
40810 // hidden the day picker
40811 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40817 p.showMonthPicker.defer(100, p);
40823 beforeBlur : function(){
40824 var v = this.parseDate(this.getRawValue());
40830 /** @cfg {Boolean} grow @hide */
40831 /** @cfg {Number} growMin @hide */
40832 /** @cfg {Number} growMax @hide */
40839 * Ext JS Library 1.1.1
40840 * Copyright(c) 2006-2007, Ext JS, LLC.
40842 * Originally Released Under LGPL - original licence link has changed is not relivant.
40845 * <script type="text/javascript">
40850 * @class Roo.form.ComboBox
40851 * @extends Roo.form.TriggerField
40852 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40854 * Create a new ComboBox.
40855 * @param {Object} config Configuration options
40857 Roo.form.ComboBox = function(config){
40858 Roo.form.ComboBox.superclass.constructor.call(this, config);
40862 * Fires when the dropdown list is expanded
40863 * @param {Roo.form.ComboBox} combo This combo box
40868 * Fires when the dropdown list is collapsed
40869 * @param {Roo.form.ComboBox} combo This combo box
40873 * @event beforeselect
40874 * Fires before a list item is selected. Return false to cancel the selection.
40875 * @param {Roo.form.ComboBox} combo This combo box
40876 * @param {Roo.data.Record} record The data record returned from the underlying store
40877 * @param {Number} index The index of the selected item in the dropdown list
40879 'beforeselect' : true,
40882 * Fires when a list item is selected
40883 * @param {Roo.form.ComboBox} combo This combo box
40884 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40885 * @param {Number} index The index of the selected item in the dropdown list
40889 * @event beforequery
40890 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40891 * The event object passed has these properties:
40892 * @param {Roo.form.ComboBox} combo This combo box
40893 * @param {String} query The query
40894 * @param {Boolean} forceAll true to force "all" query
40895 * @param {Boolean} cancel true to cancel the query
40896 * @param {Object} e The query event object
40898 'beforequery': true,
40901 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40902 * @param {Roo.form.ComboBox} combo This combo box
40907 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40908 * @param {Roo.form.ComboBox} combo This combo box
40909 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40915 if(this.transform){
40916 this.allowDomMove = false;
40917 var s = Roo.getDom(this.transform);
40918 if(!this.hiddenName){
40919 this.hiddenName = s.name;
40922 this.mode = 'local';
40923 var d = [], opts = s.options;
40924 for(var i = 0, len = opts.length;i < len; i++){
40926 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40928 this.value = value;
40930 d.push([value, o.text]);
40932 this.store = new Roo.data.SimpleStore({
40934 fields: ['value', 'text'],
40937 this.valueField = 'value';
40938 this.displayField = 'text';
40940 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40941 if(!this.lazyRender){
40942 this.target = true;
40943 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40944 s.parentNode.removeChild(s); // remove it
40945 this.render(this.el.parentNode);
40947 s.parentNode.removeChild(s); // remove it
40952 this.store = Roo.factory(this.store, Roo.data);
40955 this.selectedIndex = -1;
40956 if(this.mode == 'local'){
40957 if(config.queryDelay === undefined){
40958 this.queryDelay = 10;
40960 if(config.minChars === undefined){
40966 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40968 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40971 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40972 * rendering into an Roo.Editor, defaults to false)
40975 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40976 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40979 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40982 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40983 * the dropdown list (defaults to undefined, with no header element)
40987 * @cfg {String/Roo.Template} tpl The template to use to render the output
40991 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40993 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40995 listWidth: undefined,
40997 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40998 * mode = 'remote' or 'text' if mode = 'local')
41000 displayField: undefined,
41002 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41003 * mode = 'remote' or 'value' if mode = 'local').
41004 * Note: use of a valueField requires the user make a selection
41005 * in order for a value to be mapped.
41007 valueField: undefined,
41011 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41012 * field's data value (defaults to the underlying DOM element's name)
41014 hiddenName: undefined,
41016 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41020 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41022 selectedClass: 'x-combo-selected',
41024 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41025 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41026 * which displays a downward arrow icon).
41028 triggerClass : 'x-form-arrow-trigger',
41030 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41034 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41035 * anchor positions (defaults to 'tl-bl')
41037 listAlign: 'tl-bl?',
41039 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41043 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41044 * query specified by the allQuery config option (defaults to 'query')
41046 triggerAction: 'query',
41048 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41049 * (defaults to 4, does not apply if editable = false)
41053 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41054 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41058 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41059 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41063 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41064 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41068 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41069 * when editable = true (defaults to false)
41071 selectOnFocus:false,
41073 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41075 queryParam: 'query',
41077 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41078 * when mode = 'remote' (defaults to 'Loading...')
41080 loadingText: 'Loading...',
41082 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41086 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41090 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41091 * traditional select (defaults to true)
41095 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41099 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41103 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41104 * listWidth has a higher value)
41108 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41109 * allow the user to set arbitrary text into the field (defaults to false)
41111 forceSelection:false,
41113 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41114 * if typeAhead = true (defaults to 250)
41116 typeAheadDelay : 250,
41118 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41119 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41121 valueNotFoundText : undefined,
41123 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41125 blockFocus : false,
41128 * @cfg {Boolean} disableClear Disable showing of clear button.
41130 disableClear : false,
41132 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41134 alwaysQuery : false,
41140 // element that contains real text value.. (when hidden is used..)
41143 onRender : function(ct, position){
41144 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41145 if(this.hiddenName){
41146 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41148 this.hiddenField.value =
41149 this.hiddenValue !== undefined ? this.hiddenValue :
41150 this.value !== undefined ? this.value : '';
41152 // prevent input submission
41153 this.el.dom.removeAttribute('name');
41158 this.el.dom.setAttribute('autocomplete', 'off');
41161 var cls = 'x-combo-list';
41163 this.list = new Roo.Layer({
41164 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41167 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41168 this.list.setWidth(lw);
41169 this.list.swallowEvent('mousewheel');
41170 this.assetHeight = 0;
41173 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41174 this.assetHeight += this.header.getHeight();
41177 this.innerList = this.list.createChild({cls:cls+'-inner'});
41178 this.innerList.on('mouseover', this.onViewOver, this);
41179 this.innerList.on('mousemove', this.onViewMove, this);
41180 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41182 if(this.allowBlank && !this.pageSize && !this.disableClear){
41183 this.footer = this.list.createChild({cls:cls+'-ft'});
41184 this.pageTb = new Roo.Toolbar(this.footer);
41188 this.footer = this.list.createChild({cls:cls+'-ft'});
41189 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41190 {pageSize: this.pageSize});
41194 if (this.pageTb && this.allowBlank && !this.disableClear) {
41196 this.pageTb.add(new Roo.Toolbar.Fill(), {
41197 cls: 'x-btn-icon x-btn-clear',
41199 handler: function()
41202 _this.clearValue();
41203 _this.onSelect(false, -1);
41208 this.assetHeight += this.footer.getHeight();
41213 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41216 this.view = new Roo.View(this.innerList, this.tpl, {
41217 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41220 this.view.on('click', this.onViewClick, this);
41222 this.store.on('beforeload', this.onBeforeLoad, this);
41223 this.store.on('load', this.onLoad, this);
41224 this.store.on('loadexception', this.onLoadException, this);
41226 if(this.resizable){
41227 this.resizer = new Roo.Resizable(this.list, {
41228 pinned:true, handles:'se'
41230 this.resizer.on('resize', function(r, w, h){
41231 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41232 this.listWidth = w;
41233 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41234 this.restrictHeight();
41236 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41238 if(!this.editable){
41239 this.editable = true;
41240 this.setEditable(false);
41244 if (typeof(this.events.add.listeners) != 'undefined') {
41246 this.addicon = this.wrap.createChild(
41247 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41249 this.addicon.on('click', function(e) {
41250 this.fireEvent('add', this);
41253 if (typeof(this.events.edit.listeners) != 'undefined') {
41255 this.editicon = this.wrap.createChild(
41256 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41257 if (this.addicon) {
41258 this.editicon.setStyle('margin-left', '40px');
41260 this.editicon.on('click', function(e) {
41262 // we fire even if inothing is selected..
41263 this.fireEvent('edit', this, this.lastData );
41273 initEvents : function(){
41274 Roo.form.ComboBox.superclass.initEvents.call(this);
41276 this.keyNav = new Roo.KeyNav(this.el, {
41277 "up" : function(e){
41278 this.inKeyMode = true;
41282 "down" : function(e){
41283 if(!this.isExpanded()){
41284 this.onTriggerClick();
41286 this.inKeyMode = true;
41291 "enter" : function(e){
41292 this.onViewClick();
41296 "esc" : function(e){
41300 "tab" : function(e){
41301 this.onViewClick(false);
41302 this.fireEvent("specialkey", this, e);
41308 doRelay : function(foo, bar, hname){
41309 if(hname == 'down' || this.scope.isExpanded()){
41310 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41317 this.queryDelay = Math.max(this.queryDelay || 10,
41318 this.mode == 'local' ? 10 : 250);
41319 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41320 if(this.typeAhead){
41321 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41323 if(this.editable !== false){
41324 this.el.on("keyup", this.onKeyUp, this);
41326 if(this.forceSelection){
41327 this.on('blur', this.doForce, this);
41331 onDestroy : function(){
41333 this.view.setStore(null);
41334 this.view.el.removeAllListeners();
41335 this.view.el.remove();
41336 this.view.purgeListeners();
41339 this.list.destroy();
41342 this.store.un('beforeload', this.onBeforeLoad, this);
41343 this.store.un('load', this.onLoad, this);
41344 this.store.un('loadexception', this.onLoadException, this);
41346 Roo.form.ComboBox.superclass.onDestroy.call(this);
41350 fireKey : function(e){
41351 if(e.isNavKeyPress() && !this.list.isVisible()){
41352 this.fireEvent("specialkey", this, e);
41357 onResize: function(w, h){
41358 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41360 if(typeof w != 'number'){
41361 // we do not handle it!?!?
41364 var tw = this.trigger.getWidth();
41365 tw += this.addicon ? this.addicon.getWidth() : 0;
41366 tw += this.editicon ? this.editicon.getWidth() : 0;
41368 this.el.setWidth( this.adjustWidth('input', x));
41370 this.trigger.setStyle('left', x+'px');
41372 if(this.list && this.listWidth === undefined){
41373 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41374 this.list.setWidth(lw);
41375 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41383 * Allow or prevent the user from directly editing the field text. If false is passed,
41384 * the user will only be able to select from the items defined in the dropdown list. This method
41385 * is the runtime equivalent of setting the 'editable' config option at config time.
41386 * @param {Boolean} value True to allow the user to directly edit the field text
41388 setEditable : function(value){
41389 if(value == this.editable){
41392 this.editable = value;
41394 this.el.dom.setAttribute('readOnly', true);
41395 this.el.on('mousedown', this.onTriggerClick, this);
41396 this.el.addClass('x-combo-noedit');
41398 this.el.dom.setAttribute('readOnly', false);
41399 this.el.un('mousedown', this.onTriggerClick, this);
41400 this.el.removeClass('x-combo-noedit');
41405 onBeforeLoad : function(){
41406 if(!this.hasFocus){
41409 this.innerList.update(this.loadingText ?
41410 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41411 this.restrictHeight();
41412 this.selectedIndex = -1;
41416 onLoad : function(){
41417 if(!this.hasFocus){
41420 if(this.store.getCount() > 0){
41422 this.restrictHeight();
41423 if(this.lastQuery == this.allQuery){
41425 this.el.dom.select();
41427 if(!this.selectByValue(this.value, true)){
41428 this.select(0, true);
41432 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41433 this.taTask.delay(this.typeAheadDelay);
41437 this.onEmptyResults();
41442 onLoadException : function()
41445 Roo.log(this.store.reader.jsonData);
41446 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41447 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41453 onTypeAhead : function(){
41454 if(this.store.getCount() > 0){
41455 var r = this.store.getAt(0);
41456 var newValue = r.data[this.displayField];
41457 var len = newValue.length;
41458 var selStart = this.getRawValue().length;
41459 if(selStart != len){
41460 this.setRawValue(newValue);
41461 this.selectText(selStart, newValue.length);
41467 onSelect : function(record, index){
41468 if(this.fireEvent('beforeselect', this, record, index) !== false){
41469 this.setFromData(index > -1 ? record.data : false);
41471 this.fireEvent('select', this, record, index);
41476 * Returns the currently selected field value or empty string if no value is set.
41477 * @return {String} value The selected value
41479 getValue : function(){
41480 if(this.valueField){
41481 return typeof this.value != 'undefined' ? this.value : '';
41483 return Roo.form.ComboBox.superclass.getValue.call(this);
41487 * Clears any text/value currently set in the field
41489 clearValue : function(){
41490 if(this.hiddenField){
41491 this.hiddenField.value = '';
41494 this.setRawValue('');
41495 this.lastSelectionText = '';
41500 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41501 * will be displayed in the field. If the value does not match the data value of an existing item,
41502 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41503 * Otherwise the field will be blank (although the value will still be set).
41504 * @param {String} value The value to match
41506 setValue : function(v){
41508 if(this.valueField){
41509 var r = this.findRecord(this.valueField, v);
41511 text = r.data[this.displayField];
41512 }else if(this.valueNotFoundText !== undefined){
41513 text = this.valueNotFoundText;
41516 this.lastSelectionText = text;
41517 if(this.hiddenField){
41518 this.hiddenField.value = v;
41520 Roo.form.ComboBox.superclass.setValue.call(this, text);
41524 * @property {Object} the last set data for the element
41529 * Sets the value of the field based on a object which is related to the record format for the store.
41530 * @param {Object} value the value to set as. or false on reset?
41532 setFromData : function(o){
41533 var dv = ''; // display value
41534 var vv = ''; // value value..
41536 if (this.displayField) {
41537 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41539 // this is an error condition!!!
41540 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41543 if(this.valueField){
41544 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41546 if(this.hiddenField){
41547 this.hiddenField.value = vv;
41549 this.lastSelectionText = dv;
41550 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41554 // no hidden field.. - we store the value in 'value', but still display
41555 // display field!!!!
41556 this.lastSelectionText = dv;
41557 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41563 reset : function(){
41564 // overridden so that last data is reset..
41565 this.setValue(this.resetValue);
41566 this.clearInvalid();
41567 this.lastData = false;
41569 this.view.clearSelections();
41573 findRecord : function(prop, value){
41575 if(this.store.getCount() > 0){
41576 this.store.each(function(r){
41577 if(r.data[prop] == value){
41587 getName: function()
41589 // returns hidden if it's set..
41590 if (!this.rendered) {return ''};
41591 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41595 onViewMove : function(e, t){
41596 this.inKeyMode = false;
41600 onViewOver : function(e, t){
41601 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41604 var item = this.view.findItemFromChild(t);
41606 var index = this.view.indexOf(item);
41607 this.select(index, false);
41612 onViewClick : function(doFocus)
41614 var index = this.view.getSelectedIndexes()[0];
41615 var r = this.store.getAt(index);
41617 this.onSelect(r, index);
41619 if(doFocus !== false && !this.blockFocus){
41625 restrictHeight : function(){
41626 this.innerList.dom.style.height = '';
41627 var inner = this.innerList.dom;
41628 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41629 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41630 this.list.beginUpdate();
41631 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41632 this.list.alignTo(this.el, this.listAlign);
41633 this.list.endUpdate();
41637 onEmptyResults : function(){
41642 * Returns true if the dropdown list is expanded, else false.
41644 isExpanded : function(){
41645 return this.list.isVisible();
41649 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41650 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41651 * @param {String} value The data value of the item to select
41652 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41653 * selected item if it is not currently in view (defaults to true)
41654 * @return {Boolean} True if the value matched an item in the list, else false
41656 selectByValue : function(v, scrollIntoView){
41657 if(v !== undefined && v !== null){
41658 var r = this.findRecord(this.valueField || this.displayField, v);
41660 this.select(this.store.indexOf(r), scrollIntoView);
41668 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41669 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41670 * @param {Number} index The zero-based index of the list item to select
41671 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41672 * selected item if it is not currently in view (defaults to true)
41674 select : function(index, scrollIntoView){
41675 this.selectedIndex = index;
41676 this.view.select(index);
41677 if(scrollIntoView !== false){
41678 var el = this.view.getNode(index);
41680 this.innerList.scrollChildIntoView(el, false);
41686 selectNext : function(){
41687 var ct = this.store.getCount();
41689 if(this.selectedIndex == -1){
41691 }else if(this.selectedIndex < ct-1){
41692 this.select(this.selectedIndex+1);
41698 selectPrev : function(){
41699 var ct = this.store.getCount();
41701 if(this.selectedIndex == -1){
41703 }else if(this.selectedIndex != 0){
41704 this.select(this.selectedIndex-1);
41710 onKeyUp : function(e){
41711 if(this.editable !== false && !e.isSpecialKey()){
41712 this.lastKey = e.getKey();
41713 this.dqTask.delay(this.queryDelay);
41718 validateBlur : function(){
41719 return !this.list || !this.list.isVisible();
41723 initQuery : function(){
41724 this.doQuery(this.getRawValue());
41728 doForce : function(){
41729 if(this.el.dom.value.length > 0){
41730 this.el.dom.value =
41731 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41737 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41738 * query allowing the query action to be canceled if needed.
41739 * @param {String} query The SQL query to execute
41740 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41741 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41742 * saved in the current store (defaults to false)
41744 doQuery : function(q, forceAll){
41745 if(q === undefined || q === null){
41750 forceAll: forceAll,
41754 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41758 forceAll = qe.forceAll;
41759 if(forceAll === true || (q.length >= this.minChars)){
41760 if(this.lastQuery != q || this.alwaysQuery){
41761 this.lastQuery = q;
41762 if(this.mode == 'local'){
41763 this.selectedIndex = -1;
41765 this.store.clearFilter();
41767 this.store.filter(this.displayField, q);
41771 this.store.baseParams[this.queryParam] = q;
41773 params: this.getParams(q)
41778 this.selectedIndex = -1;
41785 getParams : function(q){
41787 //p[this.queryParam] = q;
41790 p.limit = this.pageSize;
41796 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41798 collapse : function(){
41799 if(!this.isExpanded()){
41803 Roo.get(document).un('mousedown', this.collapseIf, this);
41804 Roo.get(document).un('mousewheel', this.collapseIf, this);
41805 if (!this.editable) {
41806 Roo.get(document).un('keydown', this.listKeyPress, this);
41808 this.fireEvent('collapse', this);
41812 collapseIf : function(e){
41813 if(!e.within(this.wrap) && !e.within(this.list)){
41819 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41821 expand : function(){
41822 if(this.isExpanded() || !this.hasFocus){
41825 this.list.alignTo(this.el, this.listAlign);
41827 Roo.get(document).on('mousedown', this.collapseIf, this);
41828 Roo.get(document).on('mousewheel', this.collapseIf, this);
41829 if (!this.editable) {
41830 Roo.get(document).on('keydown', this.listKeyPress, this);
41833 this.fireEvent('expand', this);
41837 // Implements the default empty TriggerField.onTriggerClick function
41838 onTriggerClick : function(){
41842 if(this.isExpanded()){
41844 if (!this.blockFocus) {
41849 this.hasFocus = true;
41850 if(this.triggerAction == 'all') {
41851 this.doQuery(this.allQuery, true);
41853 this.doQuery(this.getRawValue());
41855 if (!this.blockFocus) {
41860 listKeyPress : function(e)
41862 //Roo.log('listkeypress');
41863 // scroll to first matching element based on key pres..
41864 if (e.isSpecialKey()) {
41867 var k = String.fromCharCode(e.getKey()).toUpperCase();
41870 var csel = this.view.getSelectedNodes();
41871 var cselitem = false;
41873 var ix = this.view.indexOf(csel[0]);
41874 cselitem = this.store.getAt(ix);
41875 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41881 this.store.each(function(v) {
41883 // start at existing selection.
41884 if (cselitem.id == v.id) {
41890 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41891 match = this.store.indexOf(v);
41896 if (match === false) {
41897 return true; // no more action?
41900 this.view.select(match);
41901 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41902 sn.scrollIntoView(sn.dom.parentNode, false);
41906 * @cfg {Boolean} grow
41910 * @cfg {Number} growMin
41914 * @cfg {Number} growMax
41922 * Copyright(c) 2010-2012, Roo J Solutions Limited
41929 * @class Roo.form.ComboBoxArray
41930 * @extends Roo.form.TextField
41931 * A facebook style adder... for lists of email / people / countries etc...
41932 * pick multiple items from a combo box, and shows each one.
41934 * Fred [x] Brian [x] [Pick another |v]
41937 * For this to work: it needs various extra information
41938 * - normal combo problay has
41940 * + displayField, valueField
41942 * For our purpose...
41945 * If we change from 'extends' to wrapping...
41952 * Create a new ComboBoxArray.
41953 * @param {Object} config Configuration options
41957 Roo.form.ComboBoxArray = function(config)
41961 * @event beforeremove
41962 * Fires before remove the value from the list
41963 * @param {Roo.form.ComboBoxArray} _self This combo box array
41964 * @param {Roo.form.ComboBoxArray.Item} item removed item
41966 'beforeremove' : true,
41969 * Fires when remove the value from the list
41970 * @param {Roo.form.ComboBoxArray} _self This combo box array
41971 * @param {Roo.form.ComboBoxArray.Item} item removed item
41978 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41980 this.items = new Roo.util.MixedCollection(false);
41982 // construct the child combo...
41992 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41995 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42000 // behavies liek a hiddne field
42001 inputType: 'hidden',
42003 * @cfg {Number} width The width of the box that displays the selected element
42010 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42014 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42016 hiddenName : false,
42019 // private the array of items that are displayed..
42021 // private - the hidden field el.
42023 // private - the filed el..
42026 //validateValue : function() { return true; }, // all values are ok!
42027 //onAddClick: function() { },
42029 onRender : function(ct, position)
42032 // create the standard hidden element
42033 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42036 // give fake names to child combo;
42037 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42038 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42040 this.combo = Roo.factory(this.combo, Roo.form);
42041 this.combo.onRender(ct, position);
42042 if (typeof(this.combo.width) != 'undefined') {
42043 this.combo.onResize(this.combo.width,0);
42046 this.combo.initEvents();
42048 // assigned so form know we need to do this..
42049 this.store = this.combo.store;
42050 this.valueField = this.combo.valueField;
42051 this.displayField = this.combo.displayField ;
42054 this.combo.wrap.addClass('x-cbarray-grp');
42056 var cbwrap = this.combo.wrap.createChild(
42057 {tag: 'div', cls: 'x-cbarray-cb'},
42062 this.hiddenEl = this.combo.wrap.createChild({
42063 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42065 this.el = this.combo.wrap.createChild({
42066 tag: 'input', type:'hidden' , name: this.name, value : ''
42068 // this.el.dom.removeAttribute("name");
42071 this.outerWrap = this.combo.wrap;
42072 this.wrap = cbwrap;
42074 this.outerWrap.setWidth(this.width);
42075 this.outerWrap.dom.removeChild(this.el.dom);
42077 this.wrap.dom.appendChild(this.el.dom);
42078 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42079 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42081 this.combo.trigger.setStyle('position','relative');
42082 this.combo.trigger.setStyle('left', '0px');
42083 this.combo.trigger.setStyle('top', '2px');
42085 this.combo.el.setStyle('vertical-align', 'text-bottom');
42087 //this.trigger.setStyle('vertical-align', 'top');
42089 // this should use the code from combo really... on('add' ....)
42093 this.adder = this.outerWrap.createChild(
42094 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42096 this.adder.on('click', function(e) {
42097 _t.fireEvent('adderclick', this, e);
42101 //this.adder.on('click', this.onAddClick, _t);
42104 this.combo.on('select', function(cb, rec, ix) {
42105 this.addItem(rec.data);
42108 cb.el.dom.value = '';
42109 //cb.lastData = rec.data;
42118 getName: function()
42120 // returns hidden if it's set..
42121 if (!this.rendered) {return ''};
42122 return this.hiddenName ? this.hiddenName : this.name;
42127 onResize: function(w, h){
42130 // not sure if this is needed..
42131 //this.combo.onResize(w,h);
42133 if(typeof w != 'number'){
42134 // we do not handle it!?!?
42137 var tw = this.combo.trigger.getWidth();
42138 tw += this.addicon ? this.addicon.getWidth() : 0;
42139 tw += this.editicon ? this.editicon.getWidth() : 0;
42141 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42143 this.combo.trigger.setStyle('left', '0px');
42145 if(this.list && this.listWidth === undefined){
42146 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42147 this.list.setWidth(lw);
42148 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42155 addItem: function(rec)
42157 var valueField = this.combo.valueField;
42158 var displayField = this.combo.displayField;
42159 if (this.items.indexOfKey(rec[valueField]) > -1) {
42160 //console.log("GOT " + rec.data.id);
42164 var x = new Roo.form.ComboBoxArray.Item({
42165 //id : rec[this.idField],
42167 displayField : displayField ,
42168 tipField : displayField ,
42172 this.items.add(rec[valueField],x);
42173 // add it before the element..
42174 this.updateHiddenEl();
42175 x.render(this.outerWrap, this.wrap.dom);
42176 // add the image handler..
42179 updateHiddenEl : function()
42182 if (!this.hiddenEl) {
42186 var idField = this.combo.valueField;
42188 this.items.each(function(f) {
42189 ar.push(f.data[idField]);
42192 this.hiddenEl.dom.value = ar.join(',');
42198 this.items.clear();
42200 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42204 this.el.dom.value = '';
42205 if (this.hiddenEl) {
42206 this.hiddenEl.dom.value = '';
42210 getValue: function()
42212 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42214 setValue: function(v) // not a valid action - must use addItems..
42221 if (this.store.isLocal && (typeof(v) == 'string')) {
42222 // then we can use the store to find the values..
42223 // comma seperated at present.. this needs to allow JSON based encoding..
42224 this.hiddenEl.value = v;
42226 Roo.each(v.split(','), function(k) {
42227 Roo.log("CHECK " + this.valueField + ',' + k);
42228 var li = this.store.query(this.valueField, k);
42233 add[this.valueField] = k;
42234 add[this.displayField] = li.item(0).data[this.displayField];
42240 if (typeof(v) == 'object' ) {
42241 // then let's assume it's an array of objects..
42242 Roo.each(v, function(l) {
42250 setFromData: function(v)
42252 // this recieves an object, if setValues is called.
42254 this.el.dom.value = v[this.displayField];
42255 this.hiddenEl.dom.value = v[this.valueField];
42256 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42259 var kv = v[this.valueField];
42260 var dv = v[this.displayField];
42261 kv = typeof(kv) != 'string' ? '' : kv;
42262 dv = typeof(dv) != 'string' ? '' : dv;
42265 var keys = kv.split(',');
42266 var display = dv.split(',');
42267 for (var i = 0 ; i < keys.length; i++) {
42270 add[this.valueField] = keys[i];
42271 add[this.displayField] = display[i];
42279 * Validates the combox array value
42280 * @return {Boolean} True if the value is valid, else false
42282 validate : function(){
42283 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42284 this.clearInvalid();
42290 validateValue : function(value){
42291 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42299 isDirty : function() {
42300 if(this.disabled) {
42305 var d = Roo.decode(String(this.originalValue));
42307 return String(this.getValue()) !== String(this.originalValue);
42310 var originalValue = [];
42312 for (var i = 0; i < d.length; i++){
42313 originalValue.push(d[i][this.valueField]);
42316 return String(this.getValue()) !== String(originalValue.join(','));
42325 * @class Roo.form.ComboBoxArray.Item
42326 * @extends Roo.BoxComponent
42327 * A selected item in the list
42328 * Fred [x] Brian [x] [Pick another |v]
42331 * Create a new item.
42332 * @param {Object} config Configuration options
42335 Roo.form.ComboBoxArray.Item = function(config) {
42336 config.id = Roo.id();
42337 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42340 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42343 displayField : false,
42347 defaultAutoCreate : {
42349 cls: 'x-cbarray-item',
42356 src : Roo.BLANK_IMAGE_URL ,
42364 onRender : function(ct, position)
42366 Roo.form.Field.superclass.onRender.call(this, ct, position);
42369 var cfg = this.getAutoCreate();
42370 this.el = ct.createChild(cfg, position);
42373 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42375 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42376 this.cb.renderer(this.data) :
42377 String.format('{0}',this.data[this.displayField]);
42380 this.el.child('div').dom.setAttribute('qtip',
42381 String.format('{0}',this.data[this.tipField])
42384 this.el.child('img').on('click', this.remove, this);
42388 remove : function()
42390 if(this.cb.disabled){
42394 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42395 this.cb.items.remove(this);
42396 this.el.child('img').un('click', this.remove, this);
42398 this.cb.updateHiddenEl();
42400 this.cb.fireEvent('remove', this.cb, this);
42406 * Ext JS Library 1.1.1
42407 * Copyright(c) 2006-2007, Ext JS, LLC.
42409 * Originally Released Under LGPL - original licence link has changed is not relivant.
42412 * <script type="text/javascript">
42415 * @class Roo.form.Checkbox
42416 * @extends Roo.form.Field
42417 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42419 * Creates a new Checkbox
42420 * @param {Object} config Configuration options
42422 Roo.form.Checkbox = function(config){
42423 Roo.form.Checkbox.superclass.constructor.call(this, config);
42427 * Fires when the checkbox is checked or unchecked.
42428 * @param {Roo.form.Checkbox} this This checkbox
42429 * @param {Boolean} checked The new checked value
42435 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42437 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42439 focusClass : undefined,
42441 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42443 fieldClass: "x-form-field",
42445 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42449 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42450 * {tag: "input", type: "checkbox", autocomplete: "off"})
42452 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42454 * @cfg {String} boxLabel The text that appears beside the checkbox
42458 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42462 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42464 valueOff: '0', // value when not checked..
42466 actionMode : 'viewEl',
42469 itemCls : 'x-menu-check-item x-form-item',
42470 groupClass : 'x-menu-group-item',
42471 inputType : 'hidden',
42474 inSetChecked: false, // check that we are not calling self...
42476 inputElement: false, // real input element?
42477 basedOn: false, // ????
42479 isFormField: true, // not sure where this is needed!!!!
42481 onResize : function(){
42482 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42483 if(!this.boxLabel){
42484 this.el.alignTo(this.wrap, 'c-c');
42488 initEvents : function(){
42489 Roo.form.Checkbox.superclass.initEvents.call(this);
42490 this.el.on("click", this.onClick, this);
42491 this.el.on("change", this.onClick, this);
42495 getResizeEl : function(){
42499 getPositionEl : function(){
42504 onRender : function(ct, position){
42505 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42507 if(this.inputValue !== undefined){
42508 this.el.dom.value = this.inputValue;
42511 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42512 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42513 var viewEl = this.wrap.createChild({
42514 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42515 this.viewEl = viewEl;
42516 this.wrap.on('click', this.onClick, this);
42518 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42519 this.el.on('propertychange', this.setFromHidden, this); //ie
42524 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42525 // viewEl.on('click', this.onClick, this);
42527 //if(this.checked){
42528 this.setChecked(this.checked);
42530 //this.checked = this.el.dom;
42536 initValue : Roo.emptyFn,
42539 * Returns the checked state of the checkbox.
42540 * @return {Boolean} True if checked, else false
42542 getValue : function(){
42544 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42546 return this.valueOff;
42551 onClick : function(){
42552 if (this.disabled) {
42555 this.setChecked(!this.checked);
42557 //if(this.el.dom.checked != this.checked){
42558 // this.setValue(this.el.dom.checked);
42563 * Sets the checked state of the checkbox.
42564 * On is always based on a string comparison between inputValue and the param.
42565 * @param {Boolean/String} value - the value to set
42566 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42568 setValue : function(v,suppressEvent){
42571 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42572 //if(this.el && this.el.dom){
42573 // this.el.dom.checked = this.checked;
42574 // this.el.dom.defaultChecked = this.checked;
42576 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42577 //this.fireEvent("check", this, this.checked);
42580 setChecked : function(state,suppressEvent)
42582 if (this.inSetChecked) {
42583 this.checked = state;
42589 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42591 this.checked = state;
42592 if(suppressEvent !== true){
42593 this.fireEvent('check', this, state);
42595 this.inSetChecked = true;
42596 this.el.dom.value = state ? this.inputValue : this.valueOff;
42597 this.inSetChecked = false;
42600 // handle setting of hidden value by some other method!!?!?
42601 setFromHidden: function()
42606 //console.log("SET FROM HIDDEN");
42607 //alert('setFrom hidden');
42608 this.setValue(this.el.dom.value);
42611 onDestroy : function()
42614 Roo.get(this.viewEl).remove();
42617 Roo.form.Checkbox.superclass.onDestroy.call(this);
42620 setBoxLabel : function(str)
42622 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42627 * Ext JS Library 1.1.1
42628 * Copyright(c) 2006-2007, Ext JS, LLC.
42630 * Originally Released Under LGPL - original licence link has changed is not relivant.
42633 * <script type="text/javascript">
42637 * @class Roo.form.Radio
42638 * @extends Roo.form.Checkbox
42639 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42640 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42642 * Creates a new Radio
42643 * @param {Object} config Configuration options
42645 Roo.form.Radio = function(){
42646 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42648 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42649 inputType: 'radio',
42652 * If this radio is part of a group, it will return the selected value
42655 getGroupValue : function(){
42656 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42660 onRender : function(ct, position){
42661 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42663 if(this.inputValue !== undefined){
42664 this.el.dom.value = this.inputValue;
42667 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42668 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42669 //var viewEl = this.wrap.createChild({
42670 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42671 //this.viewEl = viewEl;
42672 //this.wrap.on('click', this.onClick, this);
42674 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42675 //this.el.on('propertychange', this.setFromHidden, this); //ie
42680 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42681 // viewEl.on('click', this.onClick, this);
42684 this.el.dom.checked = 'checked' ;
42690 });//<script type="text/javascript">
42693 * Based Ext JS Library 1.1.1
42694 * Copyright(c) 2006-2007, Ext JS, LLC.
42700 * @class Roo.HtmlEditorCore
42701 * @extends Roo.Component
42702 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42704 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42707 Roo.HtmlEditorCore = function(config){
42710 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42715 * @event initialize
42716 * Fires when the editor is fully initialized (including the iframe)
42717 * @param {Roo.HtmlEditorCore} this
42722 * Fires when the editor is first receives the focus. Any insertion must wait
42723 * until after this event.
42724 * @param {Roo.HtmlEditorCore} this
42728 * @event beforesync
42729 * Fires before the textarea is updated with content from the editor iframe. Return false
42730 * to cancel the sync.
42731 * @param {Roo.HtmlEditorCore} this
42732 * @param {String} html
42736 * @event beforepush
42737 * Fires before the iframe editor is updated with content from the textarea. Return false
42738 * to cancel the push.
42739 * @param {Roo.HtmlEditorCore} this
42740 * @param {String} html
42745 * Fires when the textarea is updated with content from the editor iframe.
42746 * @param {Roo.HtmlEditorCore} this
42747 * @param {String} html
42752 * Fires when the iframe editor is updated with content from the textarea.
42753 * @param {Roo.HtmlEditorCore} this
42754 * @param {String} html
42759 * @event editorevent
42760 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42761 * @param {Roo.HtmlEditorCore} this
42767 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42769 // defaults : white / black...
42770 this.applyBlacklists();
42777 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42781 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42787 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42792 * @cfg {Number} height (in pixels)
42796 * @cfg {Number} width (in pixels)
42801 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42804 stylesheets: false,
42809 // private properties
42810 validationEvent : false,
42812 initialized : false,
42814 sourceEditMode : false,
42815 onFocus : Roo.emptyFn,
42817 hideMode:'offsets',
42821 // blacklist + whitelisted elements..
42828 * Protected method that will not generally be called directly. It
42829 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42830 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42832 getDocMarkup : function(){
42836 // inherit styels from page...??
42837 if (this.stylesheets === false) {
42839 Roo.get(document.head).select('style').each(function(node) {
42840 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42843 Roo.get(document.head).select('link').each(function(node) {
42844 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42847 } else if (!this.stylesheets.length) {
42849 st = '<style type="text/css">' +
42850 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42856 st += '<style type="text/css">' +
42857 'IMG { cursor: pointer } ' +
42861 return '<html><head>' + st +
42862 //<style type="text/css">' +
42863 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42865 ' </head><body class="roo-htmleditor-body"></body></html>';
42869 onRender : function(ct, position)
42872 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42873 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42876 this.el.dom.style.border = '0 none';
42877 this.el.dom.setAttribute('tabIndex', -1);
42878 this.el.addClass('x-hidden hide');
42882 if(Roo.isIE){ // fix IE 1px bogus margin
42883 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42887 this.frameId = Roo.id();
42891 var iframe = this.owner.wrap.createChild({
42893 cls: 'form-control', // bootstrap..
42895 name: this.frameId,
42896 frameBorder : 'no',
42897 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42902 this.iframe = iframe.dom;
42904 this.assignDocWin();
42906 this.doc.designMode = 'on';
42909 this.doc.write(this.getDocMarkup());
42913 var task = { // must defer to wait for browser to be ready
42915 //console.log("run task?" + this.doc.readyState);
42916 this.assignDocWin();
42917 if(this.doc.body || this.doc.readyState == 'complete'){
42919 this.doc.designMode="on";
42923 Roo.TaskMgr.stop(task);
42924 this.initEditor.defer(10, this);
42931 Roo.TaskMgr.start(task);
42936 onResize : function(w, h)
42938 Roo.log('resize: ' +w + ',' + h );
42939 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42943 if(typeof w == 'number'){
42945 this.iframe.style.width = w + 'px';
42947 if(typeof h == 'number'){
42949 this.iframe.style.height = h + 'px';
42951 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42958 * Toggles the editor between standard and source edit mode.
42959 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42961 toggleSourceEdit : function(sourceEditMode){
42963 this.sourceEditMode = sourceEditMode === true;
42965 if(this.sourceEditMode){
42967 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42970 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42971 //this.iframe.className = '';
42974 //this.setSize(this.owner.wrap.getSize());
42975 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42982 * Protected method that will not generally be called directly. If you need/want
42983 * custom HTML cleanup, this is the method you should override.
42984 * @param {String} html The HTML to be cleaned
42985 * return {String} The cleaned HTML
42987 cleanHtml : function(html){
42988 html = String(html);
42989 if(html.length > 5){
42990 if(Roo.isSafari){ // strip safari nonsense
42991 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42994 if(html == ' '){
43001 * HTML Editor -> Textarea
43002 * Protected method that will not generally be called directly. Syncs the contents
43003 * of the editor iframe with the textarea.
43005 syncValue : function(){
43006 if(this.initialized){
43007 var bd = (this.doc.body || this.doc.documentElement);
43008 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43009 var html = bd.innerHTML;
43011 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43012 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43014 html = '<div style="'+m[0]+'">' + html + '</div>';
43017 html = this.cleanHtml(html);
43018 // fix up the special chars.. normaly like back quotes in word...
43019 // however we do not want to do this with chinese..
43020 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43021 var cc = b.charCodeAt();
43023 (cc >= 0x4E00 && cc < 0xA000 ) ||
43024 (cc >= 0x3400 && cc < 0x4E00 ) ||
43025 (cc >= 0xf900 && cc < 0xfb00 )
43031 if(this.owner.fireEvent('beforesync', this, html) !== false){
43032 this.el.dom.value = html;
43033 this.owner.fireEvent('sync', this, html);
43039 * Protected method that will not generally be called directly. Pushes the value of the textarea
43040 * into the iframe editor.
43042 pushValue : function(){
43043 if(this.initialized){
43044 var v = this.el.dom.value.trim();
43046 // if(v.length < 1){
43050 if(this.owner.fireEvent('beforepush', this, v) !== false){
43051 var d = (this.doc.body || this.doc.documentElement);
43053 this.cleanUpPaste();
43054 this.el.dom.value = d.innerHTML;
43055 this.owner.fireEvent('push', this, v);
43061 deferFocus : function(){
43062 this.focus.defer(10, this);
43066 focus : function(){
43067 if(this.win && !this.sourceEditMode){
43074 assignDocWin: function()
43076 var iframe = this.iframe;
43079 this.doc = iframe.contentWindow.document;
43080 this.win = iframe.contentWindow;
43082 // if (!Roo.get(this.frameId)) {
43085 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43086 // this.win = Roo.get(this.frameId).dom.contentWindow;
43088 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43092 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43093 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43098 initEditor : function(){
43099 //console.log("INIT EDITOR");
43100 this.assignDocWin();
43104 this.doc.designMode="on";
43106 this.doc.write(this.getDocMarkup());
43109 var dbody = (this.doc.body || this.doc.documentElement);
43110 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43111 // this copies styles from the containing element into thsi one..
43112 // not sure why we need all of this..
43113 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43115 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43116 //ss['background-attachment'] = 'fixed'; // w3c
43117 dbody.bgProperties = 'fixed'; // ie
43118 //Roo.DomHelper.applyStyles(dbody, ss);
43119 Roo.EventManager.on(this.doc, {
43120 //'mousedown': this.onEditorEvent,
43121 'mouseup': this.onEditorEvent,
43122 'dblclick': this.onEditorEvent,
43123 'click': this.onEditorEvent,
43124 'keyup': this.onEditorEvent,
43129 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43131 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43132 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43134 this.initialized = true;
43136 this.owner.fireEvent('initialize', this);
43141 onDestroy : function(){
43147 //for (var i =0; i < this.toolbars.length;i++) {
43148 // // fixme - ask toolbars for heights?
43149 // this.toolbars[i].onDestroy();
43152 //this.wrap.dom.innerHTML = '';
43153 //this.wrap.remove();
43158 onFirstFocus : function(){
43160 this.assignDocWin();
43163 this.activated = true;
43166 if(Roo.isGecko){ // prevent silly gecko errors
43168 var s = this.win.getSelection();
43169 if(!s.focusNode || s.focusNode.nodeType != 3){
43170 var r = s.getRangeAt(0);
43171 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43176 this.execCmd('useCSS', true);
43177 this.execCmd('styleWithCSS', false);
43180 this.owner.fireEvent('activate', this);
43184 adjustFont: function(btn){
43185 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43186 //if(Roo.isSafari){ // safari
43189 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43190 if(Roo.isSafari){ // safari
43191 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43192 v = (v < 10) ? 10 : v;
43193 v = (v > 48) ? 48 : v;
43194 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43199 v = Math.max(1, v+adjust);
43201 this.execCmd('FontSize', v );
43204 onEditorEvent : function(e)
43206 this.owner.fireEvent('editorevent', this, e);
43207 // this.updateToolbar();
43208 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43211 insertTag : function(tg)
43213 // could be a bit smarter... -> wrap the current selected tRoo..
43214 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43216 range = this.createRange(this.getSelection());
43217 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43218 wrappingNode.appendChild(range.extractContents());
43219 range.insertNode(wrappingNode);
43226 this.execCmd("formatblock", tg);
43230 insertText : function(txt)
43234 var range = this.createRange();
43235 range.deleteContents();
43236 //alert(Sender.getAttribute('label'));
43238 range.insertNode(this.doc.createTextNode(txt));
43244 * Executes a Midas editor command on the editor document and performs necessary focus and
43245 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43246 * @param {String} cmd The Midas command
43247 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43249 relayCmd : function(cmd, value){
43251 this.execCmd(cmd, value);
43252 this.owner.fireEvent('editorevent', this);
43253 //this.updateToolbar();
43254 this.owner.deferFocus();
43258 * Executes a Midas editor command directly on the editor document.
43259 * For visual commands, you should use {@link #relayCmd} instead.
43260 * <b>This should only be called after the editor is initialized.</b>
43261 * @param {String} cmd The Midas command
43262 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43264 execCmd : function(cmd, value){
43265 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43272 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43274 * @param {String} text | dom node..
43276 insertAtCursor : function(text)
43279 if(!this.activated){
43285 var r = this.doc.selection.createRange();
43296 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43300 // from jquery ui (MIT licenced)
43302 var win = this.win;
43304 if (win.getSelection && win.getSelection().getRangeAt) {
43305 range = win.getSelection().getRangeAt(0);
43306 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43307 range.insertNode(node);
43308 } else if (win.document.selection && win.document.selection.createRange) {
43309 // no firefox support
43310 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43311 win.document.selection.createRange().pasteHTML(txt);
43313 // no firefox support
43314 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43315 this.execCmd('InsertHTML', txt);
43324 mozKeyPress : function(e){
43326 var c = e.getCharCode(), cmd;
43329 c = String.fromCharCode(c).toLowerCase();
43343 this.cleanUpPaste.defer(100, this);
43351 e.preventDefault();
43359 fixKeys : function(){ // load time branching for fastest keydown performance
43361 return function(e){
43362 var k = e.getKey(), r;
43365 r = this.doc.selection.createRange();
43368 r.pasteHTML('    ');
43375 r = this.doc.selection.createRange();
43377 var target = r.parentElement();
43378 if(!target || target.tagName.toLowerCase() != 'li'){
43380 r.pasteHTML('<br />');
43386 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43387 this.cleanUpPaste.defer(100, this);
43393 }else if(Roo.isOpera){
43394 return function(e){
43395 var k = e.getKey();
43399 this.execCmd('InsertHTML','    ');
43402 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43403 this.cleanUpPaste.defer(100, this);
43408 }else if(Roo.isSafari){
43409 return function(e){
43410 var k = e.getKey();
43414 this.execCmd('InsertText','\t');
43418 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43419 this.cleanUpPaste.defer(100, this);
43427 getAllAncestors: function()
43429 var p = this.getSelectedNode();
43432 a.push(p); // push blank onto stack..
43433 p = this.getParentElement();
43437 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43441 a.push(this.doc.body);
43445 lastSelNode : false,
43448 getSelection : function()
43450 this.assignDocWin();
43451 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43454 getSelectedNode: function()
43456 // this may only work on Gecko!!!
43458 // should we cache this!!!!
43463 var range = this.createRange(this.getSelection()).cloneRange();
43466 var parent = range.parentElement();
43468 var testRange = range.duplicate();
43469 testRange.moveToElementText(parent);
43470 if (testRange.inRange(range)) {
43473 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43476 parent = parent.parentElement;
43481 // is ancestor a text element.
43482 var ac = range.commonAncestorContainer;
43483 if (ac.nodeType == 3) {
43484 ac = ac.parentNode;
43487 var ar = ac.childNodes;
43490 var other_nodes = [];
43491 var has_other_nodes = false;
43492 for (var i=0;i<ar.length;i++) {
43493 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43496 // fullly contained node.
43498 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43503 // probably selected..
43504 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43505 other_nodes.push(ar[i]);
43509 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43514 has_other_nodes = true;
43516 if (!nodes.length && other_nodes.length) {
43517 nodes= other_nodes;
43519 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43525 createRange: function(sel)
43527 // this has strange effects when using with
43528 // top toolbar - not sure if it's a great idea.
43529 //this.editor.contentWindow.focus();
43530 if (typeof sel != "undefined") {
43532 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43534 return this.doc.createRange();
43537 return this.doc.createRange();
43540 getParentElement: function()
43543 this.assignDocWin();
43544 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43546 var range = this.createRange(sel);
43549 var p = range.commonAncestorContainer;
43550 while (p.nodeType == 3) { // text node
43561 * Range intersection.. the hard stuff...
43565 * [ -- selected range --- ]
43569 * if end is before start or hits it. fail.
43570 * if start is after end or hits it fail.
43572 * if either hits (but other is outside. - then it's not
43578 // @see http://www.thismuchiknow.co.uk/?p=64.
43579 rangeIntersectsNode : function(range, node)
43581 var nodeRange = node.ownerDocument.createRange();
43583 nodeRange.selectNode(node);
43585 nodeRange.selectNodeContents(node);
43588 var rangeStartRange = range.cloneRange();
43589 rangeStartRange.collapse(true);
43591 var rangeEndRange = range.cloneRange();
43592 rangeEndRange.collapse(false);
43594 var nodeStartRange = nodeRange.cloneRange();
43595 nodeStartRange.collapse(true);
43597 var nodeEndRange = nodeRange.cloneRange();
43598 nodeEndRange.collapse(false);
43600 return rangeStartRange.compareBoundaryPoints(
43601 Range.START_TO_START, nodeEndRange) == -1 &&
43602 rangeEndRange.compareBoundaryPoints(
43603 Range.START_TO_START, nodeStartRange) == 1;
43607 rangeCompareNode : function(range, node)
43609 var nodeRange = node.ownerDocument.createRange();
43611 nodeRange.selectNode(node);
43613 nodeRange.selectNodeContents(node);
43617 range.collapse(true);
43619 nodeRange.collapse(true);
43621 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43622 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43624 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43626 var nodeIsBefore = ss == 1;
43627 var nodeIsAfter = ee == -1;
43629 if (nodeIsBefore && nodeIsAfter) {
43632 if (!nodeIsBefore && nodeIsAfter) {
43633 return 1; //right trailed.
43636 if (nodeIsBefore && !nodeIsAfter) {
43637 return 2; // left trailed.
43643 // private? - in a new class?
43644 cleanUpPaste : function()
43646 // cleans up the whole document..
43647 Roo.log('cleanuppaste');
43649 this.cleanUpChildren(this.doc.body);
43650 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43651 if (clean != this.doc.body.innerHTML) {
43652 this.doc.body.innerHTML = clean;
43657 cleanWordChars : function(input) {// change the chars to hex code
43658 var he = Roo.HtmlEditorCore;
43660 var output = input;
43661 Roo.each(he.swapCodes, function(sw) {
43662 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43664 output = output.replace(swapper, sw[1]);
43671 cleanUpChildren : function (n)
43673 if (!n.childNodes.length) {
43676 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43677 this.cleanUpChild(n.childNodes[i]);
43684 cleanUpChild : function (node)
43687 //console.log(node);
43688 if (node.nodeName == "#text") {
43689 // clean up silly Windows -- stuff?
43692 if (node.nodeName == "#comment") {
43693 node.parentNode.removeChild(node);
43694 // clean up silly Windows -- stuff?
43697 var lcname = node.tagName.toLowerCase();
43698 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43699 // whitelist of tags..
43701 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43703 node.parentNode.removeChild(node);
43708 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43710 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43711 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43713 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43714 // remove_keep_children = true;
43717 if (remove_keep_children) {
43718 this.cleanUpChildren(node);
43719 // inserts everything just before this node...
43720 while (node.childNodes.length) {
43721 var cn = node.childNodes[0];
43722 node.removeChild(cn);
43723 node.parentNode.insertBefore(cn, node);
43725 node.parentNode.removeChild(node);
43729 if (!node.attributes || !node.attributes.length) {
43730 this.cleanUpChildren(node);
43734 function cleanAttr(n,v)
43737 if (v.match(/^\./) || v.match(/^\//)) {
43740 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43743 if (v.match(/^#/)) {
43746 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43747 node.removeAttribute(n);
43751 var cwhite = this.cwhite;
43752 var cblack = this.cblack;
43754 function cleanStyle(n,v)
43756 if (v.match(/expression/)) { //XSS?? should we even bother..
43757 node.removeAttribute(n);
43761 var parts = v.split(/;/);
43764 Roo.each(parts, function(p) {
43765 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43769 var l = p.split(':').shift().replace(/\s+/g,'');
43770 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43772 if ( cwhite.length && cblack.indexOf(l) > -1) {
43773 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43774 //node.removeAttribute(n);
43778 // only allow 'c whitelisted system attributes'
43779 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43780 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43781 //node.removeAttribute(n);
43791 if (clean.length) {
43792 node.setAttribute(n, clean.join(';'));
43794 node.removeAttribute(n);
43800 for (var i = node.attributes.length-1; i > -1 ; i--) {
43801 var a = node.attributes[i];
43804 if (a.name.toLowerCase().substr(0,2)=='on') {
43805 node.removeAttribute(a.name);
43808 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43809 node.removeAttribute(a.name);
43812 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43813 cleanAttr(a.name,a.value); // fixme..
43816 if (a.name == 'style') {
43817 cleanStyle(a.name,a.value);
43820 /// clean up MS crap..
43821 // tecnically this should be a list of valid class'es..
43824 if (a.name == 'class') {
43825 if (a.value.match(/^Mso/)) {
43826 node.className = '';
43829 if (a.value.match(/^body$/)) {
43830 node.className = '';
43841 this.cleanUpChildren(node);
43847 * Clean up MS wordisms...
43849 cleanWord : function(node)
43854 this.cleanWord(this.doc.body);
43857 if (node.nodeName == "#text") {
43858 // clean up silly Windows -- stuff?
43861 if (node.nodeName == "#comment") {
43862 node.parentNode.removeChild(node);
43863 // clean up silly Windows -- stuff?
43867 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43868 node.parentNode.removeChild(node);
43872 // remove - but keep children..
43873 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43874 while (node.childNodes.length) {
43875 var cn = node.childNodes[0];
43876 node.removeChild(cn);
43877 node.parentNode.insertBefore(cn, node);
43879 node.parentNode.removeChild(node);
43880 this.iterateChildren(node, this.cleanWord);
43884 if (node.className.length) {
43886 var cn = node.className.split(/\W+/);
43888 Roo.each(cn, function(cls) {
43889 if (cls.match(/Mso[a-zA-Z]+/)) {
43894 node.className = cna.length ? cna.join(' ') : '';
43896 node.removeAttribute("class");
43900 if (node.hasAttribute("lang")) {
43901 node.removeAttribute("lang");
43904 if (node.hasAttribute("style")) {
43906 var styles = node.getAttribute("style").split(";");
43908 Roo.each(styles, function(s) {
43909 if (!s.match(/:/)) {
43912 var kv = s.split(":");
43913 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43916 // what ever is left... we allow.
43919 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43920 if (!nstyle.length) {
43921 node.removeAttribute('style');
43924 this.iterateChildren(node, this.cleanWord);
43930 * iterateChildren of a Node, calling fn each time, using this as the scole..
43931 * @param {DomNode} node node to iterate children of.
43932 * @param {Function} fn method of this class to call on each item.
43934 iterateChildren : function(node, fn)
43936 if (!node.childNodes.length) {
43939 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43940 fn.call(this, node.childNodes[i])
43946 * cleanTableWidths.
43948 * Quite often pasting from word etc.. results in tables with column and widths.
43949 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43952 cleanTableWidths : function(node)
43957 this.cleanTableWidths(this.doc.body);
43962 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43965 Roo.log(node.tagName);
43966 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43967 this.iterateChildren(node, this.cleanTableWidths);
43970 if (node.hasAttribute('width')) {
43971 node.removeAttribute('width');
43975 if (node.hasAttribute("style")) {
43978 var styles = node.getAttribute("style").split(";");
43980 Roo.each(styles, function(s) {
43981 if (!s.match(/:/)) {
43984 var kv = s.split(":");
43985 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43988 // what ever is left... we allow.
43991 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43992 if (!nstyle.length) {
43993 node.removeAttribute('style');
43997 this.iterateChildren(node, this.cleanTableWidths);
44005 domToHTML : function(currentElement, depth, nopadtext) {
44007 depth = depth || 0;
44008 nopadtext = nopadtext || false;
44010 if (!currentElement) {
44011 return this.domToHTML(this.doc.body);
44014 //Roo.log(currentElement);
44016 var allText = false;
44017 var nodeName = currentElement.nodeName;
44018 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44020 if (nodeName == '#text') {
44022 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44027 if (nodeName != 'BODY') {
44030 // Prints the node tagName, such as <A>, <IMG>, etc
44033 for(i = 0; i < currentElement.attributes.length;i++) {
44035 var aname = currentElement.attributes.item(i).name;
44036 if (!currentElement.attributes.item(i).value.length) {
44039 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44042 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44051 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44054 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44059 // Traverse the tree
44061 var currentElementChild = currentElement.childNodes.item(i);
44062 var allText = true;
44063 var innerHTML = '';
44065 while (currentElementChild) {
44066 // Formatting code (indent the tree so it looks nice on the screen)
44067 var nopad = nopadtext;
44068 if (lastnode == 'SPAN') {
44072 if (currentElementChild.nodeName == '#text') {
44073 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44074 toadd = nopadtext ? toadd : toadd.trim();
44075 if (!nopad && toadd.length > 80) {
44076 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44078 innerHTML += toadd;
44081 currentElementChild = currentElement.childNodes.item(i);
44087 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44089 // Recursively traverse the tree structure of the child node
44090 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44091 lastnode = currentElementChild.nodeName;
44093 currentElementChild=currentElement.childNodes.item(i);
44099 // The remaining code is mostly for formatting the tree
44100 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44105 ret+= "</"+tagName+">";
44111 applyBlacklists : function()
44113 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44114 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44118 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44119 if (b.indexOf(tag) > -1) {
44122 this.white.push(tag);
44126 Roo.each(w, function(tag) {
44127 if (b.indexOf(tag) > -1) {
44130 if (this.white.indexOf(tag) > -1) {
44133 this.white.push(tag);
44138 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44139 if (w.indexOf(tag) > -1) {
44142 this.black.push(tag);
44146 Roo.each(b, function(tag) {
44147 if (w.indexOf(tag) > -1) {
44150 if (this.black.indexOf(tag) > -1) {
44153 this.black.push(tag);
44158 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44159 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44163 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44164 if (b.indexOf(tag) > -1) {
44167 this.cwhite.push(tag);
44171 Roo.each(w, function(tag) {
44172 if (b.indexOf(tag) > -1) {
44175 if (this.cwhite.indexOf(tag) > -1) {
44178 this.cwhite.push(tag);
44183 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44184 if (w.indexOf(tag) > -1) {
44187 this.cblack.push(tag);
44191 Roo.each(b, function(tag) {
44192 if (w.indexOf(tag) > -1) {
44195 if (this.cblack.indexOf(tag) > -1) {
44198 this.cblack.push(tag);
44203 setStylesheets : function(stylesheets)
44205 if(typeof(stylesheets) == 'string'){
44206 Roo.get(this.iframe.contentDocument.head).createChild({
44208 rel : 'stylesheet',
44217 Roo.each(stylesheets, function(s) {
44222 Roo.get(_this.iframe.contentDocument.head).createChild({
44224 rel : 'stylesheet',
44233 removeStylesheets : function()
44237 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44242 // hide stuff that is not compatible
44256 * @event specialkey
44260 * @cfg {String} fieldClass @hide
44263 * @cfg {String} focusClass @hide
44266 * @cfg {String} autoCreate @hide
44269 * @cfg {String} inputType @hide
44272 * @cfg {String} invalidClass @hide
44275 * @cfg {String} invalidText @hide
44278 * @cfg {String} msgFx @hide
44281 * @cfg {String} validateOnBlur @hide
44285 Roo.HtmlEditorCore.white = [
44286 'area', 'br', 'img', 'input', 'hr', 'wbr',
44288 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44289 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44290 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44291 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44292 'table', 'ul', 'xmp',
44294 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44297 'dir', 'menu', 'ol', 'ul', 'dl',
44303 Roo.HtmlEditorCore.black = [
44304 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44306 'base', 'basefont', 'bgsound', 'blink', 'body',
44307 'frame', 'frameset', 'head', 'html', 'ilayer',
44308 'iframe', 'layer', 'link', 'meta', 'object',
44309 'script', 'style' ,'title', 'xml' // clean later..
44311 Roo.HtmlEditorCore.clean = [
44312 'script', 'style', 'title', 'xml'
44314 Roo.HtmlEditorCore.remove = [
44319 Roo.HtmlEditorCore.ablack = [
44323 Roo.HtmlEditorCore.aclean = [
44324 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44328 Roo.HtmlEditorCore.pwhite= [
44329 'http', 'https', 'mailto'
44332 // white listed style attributes.
44333 Roo.HtmlEditorCore.cwhite= [
44334 // 'text-align', /// default is to allow most things..
44340 // black listed style attributes.
44341 Roo.HtmlEditorCore.cblack= [
44342 // 'font-size' -- this can be set by the project
44346 Roo.HtmlEditorCore.swapCodes =[
44357 //<script type="text/javascript">
44360 * Ext JS Library 1.1.1
44361 * Copyright(c) 2006-2007, Ext JS, LLC.
44367 Roo.form.HtmlEditor = function(config){
44371 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44373 if (!this.toolbars) {
44374 this.toolbars = [];
44376 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44382 * @class Roo.form.HtmlEditor
44383 * @extends Roo.form.Field
44384 * Provides a lightweight HTML Editor component.
44386 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44388 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44389 * supported by this editor.</b><br/><br/>
44390 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44391 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44393 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44395 * @cfg {Boolean} clearUp
44399 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44404 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44409 * @cfg {Number} height (in pixels)
44413 * @cfg {Number} width (in pixels)
44418 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44421 stylesheets: false,
44425 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44430 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44436 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44441 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44449 // private properties
44450 validationEvent : false,
44452 initialized : false,
44455 onFocus : Roo.emptyFn,
44457 hideMode:'offsets',
44459 actionMode : 'container', // defaults to hiding it...
44461 defaultAutoCreate : { // modified by initCompnoent..
44463 style:"width:500px;height:300px;",
44464 autocomplete: "new-password"
44468 initComponent : function(){
44471 * @event initialize
44472 * Fires when the editor is fully initialized (including the iframe)
44473 * @param {HtmlEditor} this
44478 * Fires when the editor is first receives the focus. Any insertion must wait
44479 * until after this event.
44480 * @param {HtmlEditor} this
44484 * @event beforesync
44485 * Fires before the textarea is updated with content from the editor iframe. Return false
44486 * to cancel the sync.
44487 * @param {HtmlEditor} this
44488 * @param {String} html
44492 * @event beforepush
44493 * Fires before the iframe editor is updated with content from the textarea. Return false
44494 * to cancel the push.
44495 * @param {HtmlEditor} this
44496 * @param {String} html
44501 * Fires when the textarea is updated with content from the editor iframe.
44502 * @param {HtmlEditor} this
44503 * @param {String} html
44508 * Fires when the iframe editor is updated with content from the textarea.
44509 * @param {HtmlEditor} this
44510 * @param {String} html
44514 * @event editmodechange
44515 * Fires when the editor switches edit modes
44516 * @param {HtmlEditor} this
44517 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44519 editmodechange: true,
44521 * @event editorevent
44522 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44523 * @param {HtmlEditor} this
44527 * @event firstfocus
44528 * Fires when on first focus - needed by toolbars..
44529 * @param {HtmlEditor} this
44534 * Auto save the htmlEditor value as a file into Events
44535 * @param {HtmlEditor} this
44539 * @event savedpreview
44540 * preview the saved version of htmlEditor
44541 * @param {HtmlEditor} this
44543 savedpreview: true,
44546 * @event stylesheetsclick
44547 * Fires when press the Sytlesheets button
44548 * @param {Roo.HtmlEditorCore} this
44550 stylesheetsclick: true
44552 this.defaultAutoCreate = {
44554 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44555 autocomplete: "new-password"
44560 * Protected method that will not generally be called directly. It
44561 * is called when the editor creates its toolbar. Override this method if you need to
44562 * add custom toolbar buttons.
44563 * @param {HtmlEditor} editor
44565 createToolbar : function(editor){
44566 Roo.log("create toolbars");
44567 if (!editor.toolbars || !editor.toolbars.length) {
44568 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44571 for (var i =0 ; i < editor.toolbars.length;i++) {
44572 editor.toolbars[i] = Roo.factory(
44573 typeof(editor.toolbars[i]) == 'string' ?
44574 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44575 Roo.form.HtmlEditor);
44576 editor.toolbars[i].init(editor);
44584 onRender : function(ct, position)
44587 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44589 this.wrap = this.el.wrap({
44590 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44593 this.editorcore.onRender(ct, position);
44595 if (this.resizable) {
44596 this.resizeEl = new Roo.Resizable(this.wrap, {
44600 minHeight : this.height,
44601 height: this.height,
44602 handles : this.resizable,
44605 resize : function(r, w, h) {
44606 _t.onResize(w,h); // -something
44612 this.createToolbar(this);
44616 this.setSize(this.wrap.getSize());
44618 if (this.resizeEl) {
44619 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44620 // should trigger onReize..
44623 this.keyNav = new Roo.KeyNav(this.el, {
44625 "tab" : function(e){
44626 e.preventDefault();
44628 var value = this.getValue();
44630 var start = this.el.dom.selectionStart;
44631 var end = this.el.dom.selectionEnd;
44635 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44636 this.el.dom.setSelectionRange(end + 1, end + 1);
44640 var f = value.substring(0, start).split("\t");
44642 if(f.pop().length != 0){
44646 this.setValue(f.join("\t") + value.substring(end));
44647 this.el.dom.setSelectionRange(start - 1, start - 1);
44651 "home" : function(e){
44652 e.preventDefault();
44654 var curr = this.el.dom.selectionStart;
44655 var lines = this.getValue().split("\n");
44662 this.el.dom.setSelectionRange(0, 0);
44668 for (var i = 0; i < lines.length;i++) {
44669 pos += lines[i].length;
44679 pos -= lines[i].length;
44685 this.el.dom.setSelectionRange(pos, pos);
44689 this.el.dom.selectionStart = pos;
44690 this.el.dom.selectionEnd = curr;
44693 "end" : function(e){
44694 e.preventDefault();
44696 var curr = this.el.dom.selectionStart;
44697 var lines = this.getValue().split("\n");
44704 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44710 for (var i = 0; i < lines.length;i++) {
44712 pos += lines[i].length;
44726 this.el.dom.setSelectionRange(pos, pos);
44730 this.el.dom.selectionStart = curr;
44731 this.el.dom.selectionEnd = pos;
44736 doRelay : function(foo, bar, hname){
44737 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44743 // if(this.autosave && this.w){
44744 // this.autoSaveFn = setInterval(this.autosave, 1000);
44749 onResize : function(w, h)
44751 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44756 if(typeof w == 'number'){
44757 var aw = w - this.wrap.getFrameWidth('lr');
44758 this.el.setWidth(this.adjustWidth('textarea', aw));
44761 if(typeof h == 'number'){
44763 for (var i =0; i < this.toolbars.length;i++) {
44764 // fixme - ask toolbars for heights?
44765 tbh += this.toolbars[i].tb.el.getHeight();
44766 if (this.toolbars[i].footer) {
44767 tbh += this.toolbars[i].footer.el.getHeight();
44774 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44775 ah -= 5; // knock a few pixes off for look..
44777 this.el.setHeight(this.adjustWidth('textarea', ah));
44781 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44782 this.editorcore.onResize(ew,eh);
44787 * Toggles the editor between standard and source edit mode.
44788 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44790 toggleSourceEdit : function(sourceEditMode)
44792 this.editorcore.toggleSourceEdit(sourceEditMode);
44794 if(this.editorcore.sourceEditMode){
44795 Roo.log('editor - showing textarea');
44798 // Roo.log(this.syncValue());
44799 this.editorcore.syncValue();
44800 this.el.removeClass('x-hidden');
44801 this.el.dom.removeAttribute('tabIndex');
44804 for (var i = 0; i < this.toolbars.length; i++) {
44805 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44806 this.toolbars[i].tb.hide();
44807 this.toolbars[i].footer.hide();
44812 Roo.log('editor - hiding textarea');
44814 // Roo.log(this.pushValue());
44815 this.editorcore.pushValue();
44817 this.el.addClass('x-hidden');
44818 this.el.dom.setAttribute('tabIndex', -1);
44820 for (var i = 0; i < this.toolbars.length; i++) {
44821 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44822 this.toolbars[i].tb.show();
44823 this.toolbars[i].footer.show();
44827 //this.deferFocus();
44830 this.setSize(this.wrap.getSize());
44831 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44833 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44836 // private (for BoxComponent)
44837 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44839 // private (for BoxComponent)
44840 getResizeEl : function(){
44844 // private (for BoxComponent)
44845 getPositionEl : function(){
44850 initEvents : function(){
44851 this.originalValue = this.getValue();
44855 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44858 markInvalid : Roo.emptyFn,
44860 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44863 clearInvalid : Roo.emptyFn,
44865 setValue : function(v){
44866 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44867 this.editorcore.pushValue();
44872 deferFocus : function(){
44873 this.focus.defer(10, this);
44877 focus : function(){
44878 this.editorcore.focus();
44884 onDestroy : function(){
44890 for (var i =0; i < this.toolbars.length;i++) {
44891 // fixme - ask toolbars for heights?
44892 this.toolbars[i].onDestroy();
44895 this.wrap.dom.innerHTML = '';
44896 this.wrap.remove();
44901 onFirstFocus : function(){
44902 //Roo.log("onFirstFocus");
44903 this.editorcore.onFirstFocus();
44904 for (var i =0; i < this.toolbars.length;i++) {
44905 this.toolbars[i].onFirstFocus();
44911 syncValue : function()
44913 this.editorcore.syncValue();
44916 pushValue : function()
44918 this.editorcore.pushValue();
44921 setStylesheets : function(stylesheets)
44923 this.editorcore.setStylesheets(stylesheets);
44926 removeStylesheets : function()
44928 this.editorcore.removeStylesheets();
44932 // hide stuff that is not compatible
44946 * @event specialkey
44950 * @cfg {String} fieldClass @hide
44953 * @cfg {String} focusClass @hide
44956 * @cfg {String} autoCreate @hide
44959 * @cfg {String} inputType @hide
44962 * @cfg {String} invalidClass @hide
44965 * @cfg {String} invalidText @hide
44968 * @cfg {String} msgFx @hide
44971 * @cfg {String} validateOnBlur @hide
44975 // <script type="text/javascript">
44978 * Ext JS Library 1.1.1
44979 * Copyright(c) 2006-2007, Ext JS, LLC.
44985 * @class Roo.form.HtmlEditorToolbar1
44990 new Roo.form.HtmlEditor({
44993 new Roo.form.HtmlEditorToolbar1({
44994 disable : { fonts: 1 , format: 1, ..., ... , ...],
45000 * @cfg {Object} disable List of elements to disable..
45001 * @cfg {Array} btns List of additional buttons.
45005 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45008 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45011 Roo.apply(this, config);
45013 // default disabled, based on 'good practice'..
45014 this.disable = this.disable || {};
45015 Roo.applyIf(this.disable, {
45018 specialElements : true
45022 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45023 // dont call parent... till later.
45026 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45033 editorcore : false,
45035 * @cfg {Object} disable List of toolbar elements to disable
45042 * @cfg {String} createLinkText The default text for the create link prompt
45044 createLinkText : 'Please enter the URL for the link:',
45046 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45048 defaultLinkValue : 'http:/'+'/',
45052 * @cfg {Array} fontFamilies An array of available font families
45070 // "á" , ?? a acute?
45075 "°" // , // degrees
45077 // "é" , // e ecute
45078 // "ú" , // u ecute?
45081 specialElements : [
45083 text: "Insert Table",
45086 ihtml : '<table><tr><td>Cell</td></tr></table>'
45090 text: "Insert Image",
45093 ihtml : '<img src="about:blank"/>'
45102 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45103 "input:submit", "input:button", "select", "textarea", "label" ],
45106 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45108 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45116 * @cfg {String} defaultFont default font to use.
45118 defaultFont: 'tahoma',
45120 fontSelect : false,
45123 formatCombo : false,
45125 init : function(editor)
45127 this.editor = editor;
45128 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45129 var editorcore = this.editorcore;
45133 var fid = editorcore.frameId;
45135 function btn(id, toggle, handler){
45136 var xid = fid + '-'+ id ;
45140 cls : 'x-btn-icon x-edit-'+id,
45141 enableToggle:toggle !== false,
45142 scope: _t, // was editor...
45143 handler:handler||_t.relayBtnCmd,
45144 clickEvent:'mousedown',
45145 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45152 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45154 // stop form submits
45155 tb.el.on('click', function(e){
45156 e.preventDefault(); // what does this do?
45159 if(!this.disable.font) { // && !Roo.isSafari){
45160 /* why no safari for fonts
45161 editor.fontSelect = tb.el.createChild({
45164 cls:'x-font-select',
45165 html: this.createFontOptions()
45168 editor.fontSelect.on('change', function(){
45169 var font = editor.fontSelect.dom.value;
45170 editor.relayCmd('fontname', font);
45171 editor.deferFocus();
45175 editor.fontSelect.dom,
45181 if(!this.disable.formats){
45182 this.formatCombo = new Roo.form.ComboBox({
45183 store: new Roo.data.SimpleStore({
45186 data : this.formats // from states.js
45190 //autoCreate : {tag: "div", size: "20"},
45191 displayField:'tag',
45195 triggerAction: 'all',
45196 emptyText:'Add tag',
45197 selectOnFocus:true,
45200 'select': function(c, r, i) {
45201 editorcore.insertTag(r.get('tag'));
45207 tb.addField(this.formatCombo);
45211 if(!this.disable.format){
45216 btn('strikethrough')
45219 if(!this.disable.fontSize){
45224 btn('increasefontsize', false, editorcore.adjustFont),
45225 btn('decreasefontsize', false, editorcore.adjustFont)
45230 if(!this.disable.colors){
45233 id:editorcore.frameId +'-forecolor',
45234 cls:'x-btn-icon x-edit-forecolor',
45235 clickEvent:'mousedown',
45236 tooltip: this.buttonTips['forecolor'] || undefined,
45238 menu : new Roo.menu.ColorMenu({
45239 allowReselect: true,
45240 focus: Roo.emptyFn,
45243 selectHandler: function(cp, color){
45244 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45245 editor.deferFocus();
45248 clickEvent:'mousedown'
45251 id:editorcore.frameId +'backcolor',
45252 cls:'x-btn-icon x-edit-backcolor',
45253 clickEvent:'mousedown',
45254 tooltip: this.buttonTips['backcolor'] || undefined,
45256 menu : new Roo.menu.ColorMenu({
45257 focus: Roo.emptyFn,
45260 allowReselect: true,
45261 selectHandler: function(cp, color){
45263 editorcore.execCmd('useCSS', false);
45264 editorcore.execCmd('hilitecolor', color);
45265 editorcore.execCmd('useCSS', true);
45266 editor.deferFocus();
45268 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45269 Roo.isSafari || Roo.isIE ? '#'+color : color);
45270 editor.deferFocus();
45274 clickEvent:'mousedown'
45279 // now add all the items...
45282 if(!this.disable.alignments){
45285 btn('justifyleft'),
45286 btn('justifycenter'),
45287 btn('justifyright')
45291 //if(!Roo.isSafari){
45292 if(!this.disable.links){
45295 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45299 if(!this.disable.lists){
45302 btn('insertorderedlist'),
45303 btn('insertunorderedlist')
45306 if(!this.disable.sourceEdit){
45309 btn('sourceedit', true, function(btn){
45310 this.toggleSourceEdit(btn.pressed);
45317 // special menu.. - needs to be tidied up..
45318 if (!this.disable.special) {
45321 cls: 'x-edit-none',
45327 for (var i =0; i < this.specialChars.length; i++) {
45328 smenu.menu.items.push({
45330 html: this.specialChars[i],
45331 handler: function(a,b) {
45332 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45333 //editor.insertAtCursor(a.html);
45347 if (!this.disable.cleanStyles) {
45349 cls: 'x-btn-icon x-btn-clear',
45355 for (var i =0; i < this.cleanStyles.length; i++) {
45356 cmenu.menu.items.push({
45357 actiontype : this.cleanStyles[i],
45358 html: 'Remove ' + this.cleanStyles[i],
45359 handler: function(a,b) {
45362 var c = Roo.get(editorcore.doc.body);
45363 c.select('[style]').each(function(s) {
45364 s.dom.style.removeProperty(a.actiontype);
45366 editorcore.syncValue();
45371 cmenu.menu.items.push({
45372 actiontype : 'tablewidths',
45373 html: 'Remove Table Widths',
45374 handler: function(a,b) {
45375 editorcore.cleanTableWidths();
45376 editorcore.syncValue();
45380 cmenu.menu.items.push({
45381 actiontype : 'word',
45382 html: 'Remove MS Word Formating',
45383 handler: function(a,b) {
45384 editorcore.cleanWord();
45385 editorcore.syncValue();
45390 cmenu.menu.items.push({
45391 actiontype : 'all',
45392 html: 'Remove All Styles',
45393 handler: function(a,b) {
45395 var c = Roo.get(editorcore.doc.body);
45396 c.select('[style]').each(function(s) {
45397 s.dom.removeAttribute('style');
45399 editorcore.syncValue();
45404 cmenu.menu.items.push({
45405 actiontype : 'all',
45406 html: 'Remove All CSS Classes',
45407 handler: function(a,b) {
45409 var c = Roo.get(editorcore.doc.body);
45410 c.select('[class]').each(function(s) {
45411 s.dom.className = '';
45413 editorcore.syncValue();
45418 cmenu.menu.items.push({
45419 actiontype : 'tidy',
45420 html: 'Tidy HTML Source',
45421 handler: function(a,b) {
45422 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45423 editorcore.syncValue();
45432 if (!this.disable.specialElements) {
45435 cls: 'x-edit-none',
45440 for (var i =0; i < this.specialElements.length; i++) {
45441 semenu.menu.items.push(
45443 handler: function(a,b) {
45444 editor.insertAtCursor(this.ihtml);
45446 }, this.specialElements[i])
45458 for(var i =0; i< this.btns.length;i++) {
45459 var b = Roo.factory(this.btns[i],Roo.form);
45460 b.cls = 'x-edit-none';
45462 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45463 b.cls += ' x-init-enable';
45466 b.scope = editorcore;
45474 // disable everything...
45476 this.tb.items.each(function(item){
45479 item.id != editorcore.frameId+ '-sourceedit' &&
45480 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45486 this.rendered = true;
45488 // the all the btns;
45489 editor.on('editorevent', this.updateToolbar, this);
45490 // other toolbars need to implement this..
45491 //editor.on('editmodechange', this.updateToolbar, this);
45495 relayBtnCmd : function(btn) {
45496 this.editorcore.relayCmd(btn.cmd);
45498 // private used internally
45499 createLink : function(){
45500 Roo.log("create link?");
45501 var url = prompt(this.createLinkText, this.defaultLinkValue);
45502 if(url && url != 'http:/'+'/'){
45503 this.editorcore.relayCmd('createlink', url);
45509 * Protected method that will not generally be called directly. It triggers
45510 * a toolbar update by reading the markup state of the current selection in the editor.
45512 updateToolbar: function(){
45514 if(!this.editorcore.activated){
45515 this.editor.onFirstFocus();
45519 var btns = this.tb.items.map,
45520 doc = this.editorcore.doc,
45521 frameId = this.editorcore.frameId;
45523 if(!this.disable.font && !Roo.isSafari){
45525 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45526 if(name != this.fontSelect.dom.value){
45527 this.fontSelect.dom.value = name;
45531 if(!this.disable.format){
45532 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45533 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45534 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45535 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45537 if(!this.disable.alignments){
45538 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45539 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45540 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45542 if(!Roo.isSafari && !this.disable.lists){
45543 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45544 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45547 var ans = this.editorcore.getAllAncestors();
45548 if (this.formatCombo) {
45551 var store = this.formatCombo.store;
45552 this.formatCombo.setValue("");
45553 for (var i =0; i < ans.length;i++) {
45554 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45556 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45564 // hides menus... - so this cant be on a menu...
45565 Roo.menu.MenuMgr.hideAll();
45567 //this.editorsyncValue();
45571 createFontOptions : function(){
45572 var buf = [], fs = this.fontFamilies, ff, lc;
45576 for(var i = 0, len = fs.length; i< len; i++){
45578 lc = ff.toLowerCase();
45580 '<option value="',lc,'" style="font-family:',ff,';"',
45581 (this.defaultFont == lc ? ' selected="true">' : '>'),
45586 return buf.join('');
45589 toggleSourceEdit : function(sourceEditMode){
45591 Roo.log("toolbar toogle");
45592 if(sourceEditMode === undefined){
45593 sourceEditMode = !this.sourceEditMode;
45595 this.sourceEditMode = sourceEditMode === true;
45596 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45597 // just toggle the button?
45598 if(btn.pressed !== this.sourceEditMode){
45599 btn.toggle(this.sourceEditMode);
45603 if(sourceEditMode){
45604 Roo.log("disabling buttons");
45605 this.tb.items.each(function(item){
45606 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45612 Roo.log("enabling buttons");
45613 if(this.editorcore.initialized){
45614 this.tb.items.each(function(item){
45620 Roo.log("calling toggole on editor");
45621 // tell the editor that it's been pressed..
45622 this.editor.toggleSourceEdit(sourceEditMode);
45626 * Object collection of toolbar tooltips for the buttons in the editor. The key
45627 * is the command id associated with that button and the value is a valid QuickTips object.
45632 title: 'Bold (Ctrl+B)',
45633 text: 'Make the selected text bold.',
45634 cls: 'x-html-editor-tip'
45637 title: 'Italic (Ctrl+I)',
45638 text: 'Make the selected text italic.',
45639 cls: 'x-html-editor-tip'
45647 title: 'Bold (Ctrl+B)',
45648 text: 'Make the selected text bold.',
45649 cls: 'x-html-editor-tip'
45652 title: 'Italic (Ctrl+I)',
45653 text: 'Make the selected text italic.',
45654 cls: 'x-html-editor-tip'
45657 title: 'Underline (Ctrl+U)',
45658 text: 'Underline the selected text.',
45659 cls: 'x-html-editor-tip'
45662 title: 'Strikethrough',
45663 text: 'Strikethrough the selected text.',
45664 cls: 'x-html-editor-tip'
45666 increasefontsize : {
45667 title: 'Grow Text',
45668 text: 'Increase the font size.',
45669 cls: 'x-html-editor-tip'
45671 decreasefontsize : {
45672 title: 'Shrink Text',
45673 text: 'Decrease the font size.',
45674 cls: 'x-html-editor-tip'
45677 title: 'Text Highlight Color',
45678 text: 'Change the background color of the selected text.',
45679 cls: 'x-html-editor-tip'
45682 title: 'Font Color',
45683 text: 'Change the color of the selected text.',
45684 cls: 'x-html-editor-tip'
45687 title: 'Align Text Left',
45688 text: 'Align text to the left.',
45689 cls: 'x-html-editor-tip'
45692 title: 'Center Text',
45693 text: 'Center text in the editor.',
45694 cls: 'x-html-editor-tip'
45697 title: 'Align Text Right',
45698 text: 'Align text to the right.',
45699 cls: 'x-html-editor-tip'
45701 insertunorderedlist : {
45702 title: 'Bullet List',
45703 text: 'Start a bulleted list.',
45704 cls: 'x-html-editor-tip'
45706 insertorderedlist : {
45707 title: 'Numbered List',
45708 text: 'Start a numbered list.',
45709 cls: 'x-html-editor-tip'
45712 title: 'Hyperlink',
45713 text: 'Make the selected text a hyperlink.',
45714 cls: 'x-html-editor-tip'
45717 title: 'Source Edit',
45718 text: 'Switch to source editing mode.',
45719 cls: 'x-html-editor-tip'
45723 onDestroy : function(){
45726 this.tb.items.each(function(item){
45728 item.menu.removeAll();
45730 item.menu.el.destroy();
45738 onFirstFocus: function() {
45739 this.tb.items.each(function(item){
45748 // <script type="text/javascript">
45751 * Ext JS Library 1.1.1
45752 * Copyright(c) 2006-2007, Ext JS, LLC.
45759 * @class Roo.form.HtmlEditor.ToolbarContext
45764 new Roo.form.HtmlEditor({
45767 { xtype: 'ToolbarStandard', styles : {} }
45768 { xtype: 'ToolbarContext', disable : {} }
45774 * @config : {Object} disable List of elements to disable.. (not done yet.)
45775 * @config : {Object} styles Map of styles available.
45779 Roo.form.HtmlEditor.ToolbarContext = function(config)
45782 Roo.apply(this, config);
45783 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45784 // dont call parent... till later.
45785 this.styles = this.styles || {};
45790 Roo.form.HtmlEditor.ToolbarContext.types = {
45802 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45868 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45873 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45883 style : 'fontFamily',
45884 displayField: 'display',
45885 optname : 'font-family',
45934 // should we really allow this??
45935 // should this just be
45946 style : 'fontFamily',
45947 displayField: 'display',
45948 optname : 'font-family',
45955 style : 'fontFamily',
45956 displayField: 'display',
45957 optname : 'font-family',
45964 style : 'fontFamily',
45965 displayField: 'display',
45966 optname : 'font-family',
45977 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45978 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45980 Roo.form.HtmlEditor.ToolbarContext.options = {
45982 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45983 [ 'Courier New', 'Courier New'],
45984 [ 'Tahoma', 'Tahoma'],
45985 [ 'Times New Roman,serif', 'Times'],
45986 [ 'Verdana','Verdana' ]
45990 // fixme - these need to be configurable..
45993 //Roo.form.HtmlEditor.ToolbarContext.types
45996 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46003 editorcore : false,
46005 * @cfg {Object} disable List of toolbar elements to disable
46010 * @cfg {Object} styles List of styles
46011 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46013 * These must be defined in the page, so they get rendered correctly..
46024 init : function(editor)
46026 this.editor = editor;
46027 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46028 var editorcore = this.editorcore;
46030 var fid = editorcore.frameId;
46032 function btn(id, toggle, handler){
46033 var xid = fid + '-'+ id ;
46037 cls : 'x-btn-icon x-edit-'+id,
46038 enableToggle:toggle !== false,
46039 scope: editorcore, // was editor...
46040 handler:handler||editorcore.relayBtnCmd,
46041 clickEvent:'mousedown',
46042 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46046 // create a new element.
46047 var wdiv = editor.wrap.createChild({
46049 }, editor.wrap.dom.firstChild.nextSibling, true);
46051 // can we do this more than once??
46053 // stop form submits
46056 // disable everything...
46057 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46058 this.toolbars = {};
46060 for (var i in ty) {
46062 this.toolbars[i] = this.buildToolbar(ty[i],i);
46064 this.tb = this.toolbars.BODY;
46066 this.buildFooter();
46067 this.footer.show();
46068 editor.on('hide', function( ) { this.footer.hide() }, this);
46069 editor.on('show', function( ) { this.footer.show() }, this);
46072 this.rendered = true;
46074 // the all the btns;
46075 editor.on('editorevent', this.updateToolbar, this);
46076 // other toolbars need to implement this..
46077 //editor.on('editmodechange', this.updateToolbar, this);
46083 * Protected method that will not generally be called directly. It triggers
46084 * a toolbar update by reading the markup state of the current selection in the editor.
46086 * Note you can force an update by calling on('editorevent', scope, false)
46088 updateToolbar: function(editor,ev,sel){
46091 // capture mouse up - this is handy for selecting images..
46092 // perhaps should go somewhere else...
46093 if(!this.editorcore.activated){
46094 this.editor.onFirstFocus();
46100 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46101 // selectNode - might want to handle IE?
46103 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46104 ev.target && ev.target.tagName == 'IMG') {
46105 // they have click on an image...
46106 // let's see if we can change the selection...
46109 var nodeRange = sel.ownerDocument.createRange();
46111 nodeRange.selectNode(sel);
46113 nodeRange.selectNodeContents(sel);
46115 //nodeRange.collapse(true);
46116 var s = this.editorcore.win.getSelection();
46117 s.removeAllRanges();
46118 s.addRange(nodeRange);
46122 var updateFooter = sel ? false : true;
46125 var ans = this.editorcore.getAllAncestors();
46128 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46131 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46132 sel = sel ? sel : this.editorcore.doc.body;
46133 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46136 // pick a menu that exists..
46137 var tn = sel.tagName.toUpperCase();
46138 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46140 tn = sel.tagName.toUpperCase();
46142 var lastSel = this.tb.selectedNode;
46144 this.tb.selectedNode = sel;
46146 // if current menu does not match..
46148 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46151 ///console.log("show: " + tn);
46152 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46155 this.tb.items.first().el.innerHTML = tn + ': ';
46158 // update attributes
46159 if (this.tb.fields) {
46160 this.tb.fields.each(function(e) {
46162 e.setValue(sel.style[e.stylename]);
46165 e.setValue(sel.getAttribute(e.attrname));
46169 var hasStyles = false;
46170 for(var i in this.styles) {
46177 var st = this.tb.fields.item(0);
46179 st.store.removeAll();
46182 var cn = sel.className.split(/\s+/);
46185 if (this.styles['*']) {
46187 Roo.each(this.styles['*'], function(v) {
46188 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46191 if (this.styles[tn]) {
46192 Roo.each(this.styles[tn], function(v) {
46193 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46197 st.store.loadData(avs);
46201 // flag our selected Node.
46202 this.tb.selectedNode = sel;
46205 Roo.menu.MenuMgr.hideAll();
46209 if (!updateFooter) {
46210 //this.footDisp.dom.innerHTML = '';
46213 // update the footer
46217 this.footerEls = ans.reverse();
46218 Roo.each(this.footerEls, function(a,i) {
46219 if (!a) { return; }
46220 html += html.length ? ' > ' : '';
46222 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46227 var sz = this.footDisp.up('td').getSize();
46228 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46229 this.footDisp.dom.style.marginLeft = '5px';
46231 this.footDisp.dom.style.overflow = 'hidden';
46233 this.footDisp.dom.innerHTML = html;
46235 //this.editorsyncValue();
46242 onDestroy : function(){
46245 this.tb.items.each(function(item){
46247 item.menu.removeAll();
46249 item.menu.el.destroy();
46257 onFirstFocus: function() {
46258 // need to do this for all the toolbars..
46259 this.tb.items.each(function(item){
46263 buildToolbar: function(tlist, nm)
46265 var editor = this.editor;
46266 var editorcore = this.editorcore;
46267 // create a new element.
46268 var wdiv = editor.wrap.createChild({
46270 }, editor.wrap.dom.firstChild.nextSibling, true);
46273 var tb = new Roo.Toolbar(wdiv);
46276 tb.add(nm+ ": ");
46279 for(var i in this.styles) {
46284 if (styles && styles.length) {
46286 // this needs a multi-select checkbox...
46287 tb.addField( new Roo.form.ComboBox({
46288 store: new Roo.data.SimpleStore({
46290 fields: ['val', 'selected'],
46293 name : '-roo-edit-className',
46294 attrname : 'className',
46295 displayField: 'val',
46299 triggerAction: 'all',
46300 emptyText:'Select Style',
46301 selectOnFocus:true,
46304 'select': function(c, r, i) {
46305 // initial support only for on class per el..
46306 tb.selectedNode.className = r ? r.get('val') : '';
46307 editorcore.syncValue();
46314 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46315 var tbops = tbc.options;
46317 for (var i in tlist) {
46319 var item = tlist[i];
46320 tb.add(item.title + ": ");
46323 //optname == used so you can configure the options available..
46324 var opts = item.opts ? item.opts : false;
46325 if (item.optname) {
46326 opts = tbops[item.optname];
46331 // opts == pulldown..
46332 tb.addField( new Roo.form.ComboBox({
46333 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46335 fields: ['val', 'display'],
46338 name : '-roo-edit-' + i,
46340 stylename : item.style ? item.style : false,
46341 displayField: item.displayField ? item.displayField : 'val',
46342 valueField : 'val',
46344 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46346 triggerAction: 'all',
46347 emptyText:'Select',
46348 selectOnFocus:true,
46349 width: item.width ? item.width : 130,
46351 'select': function(c, r, i) {
46353 tb.selectedNode.style[c.stylename] = r.get('val');
46356 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46365 tb.addField( new Roo.form.TextField({
46368 //allowBlank:false,
46373 tb.addField( new Roo.form.TextField({
46374 name: '-roo-edit-' + i,
46381 'change' : function(f, nv, ov) {
46382 tb.selectedNode.setAttribute(f.attrname, nv);
46383 editorcore.syncValue();
46396 text: 'Stylesheets',
46399 click : function ()
46401 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46409 text: 'Remove Tag',
46412 click : function ()
46415 // undo does not work.
46417 var sn = tb.selectedNode;
46419 var pn = sn.parentNode;
46421 var stn = sn.childNodes[0];
46422 var en = sn.childNodes[sn.childNodes.length - 1 ];
46423 while (sn.childNodes.length) {
46424 var node = sn.childNodes[0];
46425 sn.removeChild(node);
46427 pn.insertBefore(node, sn);
46430 pn.removeChild(sn);
46431 var range = editorcore.createRange();
46433 range.setStart(stn,0);
46434 range.setEnd(en,0); //????
46435 //range.selectNode(sel);
46438 var selection = editorcore.getSelection();
46439 selection.removeAllRanges();
46440 selection.addRange(range);
46444 //_this.updateToolbar(null, null, pn);
46445 _this.updateToolbar(null, null, null);
46446 _this.footDisp.dom.innerHTML = '';
46456 tb.el.on('click', function(e){
46457 e.preventDefault(); // what does this do?
46459 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46462 // dont need to disable them... as they will get hidden
46467 buildFooter : function()
46470 var fel = this.editor.wrap.createChild();
46471 this.footer = new Roo.Toolbar(fel);
46472 // toolbar has scrolly on left / right?
46473 var footDisp= new Roo.Toolbar.Fill();
46479 handler : function() {
46480 _t.footDisp.scrollTo('left',0,true)
46484 this.footer.add( footDisp );
46489 handler : function() {
46491 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46495 var fel = Roo.get(footDisp.el);
46496 fel.addClass('x-editor-context');
46497 this.footDispWrap = fel;
46498 this.footDispWrap.overflow = 'hidden';
46500 this.footDisp = fel.createChild();
46501 this.footDispWrap.on('click', this.onContextClick, this)
46505 onContextClick : function (ev,dom)
46507 ev.preventDefault();
46508 var cn = dom.className;
46510 if (!cn.match(/x-ed-loc-/)) {
46513 var n = cn.split('-').pop();
46514 var ans = this.footerEls;
46518 var range = this.editorcore.createRange();
46520 range.selectNodeContents(sel);
46521 //range.selectNode(sel);
46524 var selection = this.editorcore.getSelection();
46525 selection.removeAllRanges();
46526 selection.addRange(range);
46530 this.updateToolbar(null, null, sel);
46547 * Ext JS Library 1.1.1
46548 * Copyright(c) 2006-2007, Ext JS, LLC.
46550 * Originally Released Under LGPL - original licence link has changed is not relivant.
46553 * <script type="text/javascript">
46557 * @class Roo.form.BasicForm
46558 * @extends Roo.util.Observable
46559 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46561 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46562 * @param {Object} config Configuration options
46564 Roo.form.BasicForm = function(el, config){
46565 this.allItems = [];
46566 this.childForms = [];
46567 Roo.apply(this, config);
46569 * The Roo.form.Field items in this form.
46570 * @type MixedCollection
46574 this.items = new Roo.util.MixedCollection(false, function(o){
46575 return o.id || (o.id = Roo.id());
46579 * @event beforeaction
46580 * Fires before any action is performed. Return false to cancel the action.
46581 * @param {Form} this
46582 * @param {Action} action The action to be performed
46584 beforeaction: true,
46586 * @event actionfailed
46587 * Fires when an action fails.
46588 * @param {Form} this
46589 * @param {Action} action The action that failed
46591 actionfailed : true,
46593 * @event actioncomplete
46594 * Fires when an action is completed.
46595 * @param {Form} this
46596 * @param {Action} action The action that completed
46598 actioncomplete : true
46603 Roo.form.BasicForm.superclass.constructor.call(this);
46606 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46608 * @cfg {String} method
46609 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46612 * @cfg {DataReader} reader
46613 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46614 * This is optional as there is built-in support for processing JSON.
46617 * @cfg {DataReader} errorReader
46618 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46619 * This is completely optional as there is built-in support for processing JSON.
46622 * @cfg {String} url
46623 * The URL to use for form actions if one isn't supplied in the action options.
46626 * @cfg {Boolean} fileUpload
46627 * Set to true if this form is a file upload.
46631 * @cfg {Object} baseParams
46632 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46637 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46642 activeAction : null,
46645 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46646 * or setValues() data instead of when the form was first created.
46648 trackResetOnLoad : false,
46652 * childForms - used for multi-tab forms
46655 childForms : false,
46658 * allItems - full list of fields.
46664 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46665 * element by passing it or its id or mask the form itself by passing in true.
46668 waitMsgTarget : false,
46671 initEl : function(el){
46672 this.el = Roo.get(el);
46673 this.id = this.el.id || Roo.id();
46674 this.el.on('submit', this.onSubmit, this);
46675 this.el.addClass('x-form');
46679 onSubmit : function(e){
46684 * Returns true if client-side validation on the form is successful.
46687 isValid : function(){
46689 this.items.each(function(f){
46698 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46701 isDirty : function(){
46703 this.items.each(function(f){
46713 * Returns true if any fields in this form have changed since their original load. (New version)
46717 hasChanged : function()
46720 this.items.each(function(f){
46721 if(f.hasChanged()){
46730 * Resets all hasChanged to 'false' -
46731 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46732 * So hasChanged storage is only to be used for this purpose
46735 resetHasChanged : function()
46737 this.items.each(function(f){
46738 f.resetHasChanged();
46745 * Performs a predefined action (submit or load) or custom actions you define on this form.
46746 * @param {String} actionName The name of the action type
46747 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46748 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46749 * accept other config options):
46751 Property Type Description
46752 ---------------- --------------- ----------------------------------------------------------------------------------
46753 url String The url for the action (defaults to the form's url)
46754 method String The form method to use (defaults to the form's method, or POST if not defined)
46755 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46756 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46757 validate the form on the client (defaults to false)
46759 * @return {BasicForm} this
46761 doAction : function(action, options){
46762 if(typeof action == 'string'){
46763 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46765 if(this.fireEvent('beforeaction', this, action) !== false){
46766 this.beforeAction(action);
46767 action.run.defer(100, action);
46773 * Shortcut to do a submit action.
46774 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46775 * @return {BasicForm} this
46777 submit : function(options){
46778 this.doAction('submit', options);
46783 * Shortcut to do a load action.
46784 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46785 * @return {BasicForm} this
46787 load : function(options){
46788 this.doAction('load', options);
46793 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46794 * @param {Record} record The record to edit
46795 * @return {BasicForm} this
46797 updateRecord : function(record){
46798 record.beginEdit();
46799 var fs = record.fields;
46800 fs.each(function(f){
46801 var field = this.findField(f.name);
46803 record.set(f.name, field.getValue());
46811 * Loads an Roo.data.Record into this form.
46812 * @param {Record} record The record to load
46813 * @return {BasicForm} this
46815 loadRecord : function(record){
46816 this.setValues(record.data);
46821 beforeAction : function(action){
46822 var o = action.options;
46825 if(this.waitMsgTarget === true){
46826 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46827 }else if(this.waitMsgTarget){
46828 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46829 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46831 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46837 afterAction : function(action, success){
46838 this.activeAction = null;
46839 var o = action.options;
46841 if(this.waitMsgTarget === true){
46843 }else if(this.waitMsgTarget){
46844 this.waitMsgTarget.unmask();
46846 Roo.MessageBox.updateProgress(1);
46847 Roo.MessageBox.hide();
46854 Roo.callback(o.success, o.scope, [this, action]);
46855 this.fireEvent('actioncomplete', this, action);
46859 // failure condition..
46860 // we have a scenario where updates need confirming.
46861 // eg. if a locking scenario exists..
46862 // we look for { errors : { needs_confirm : true }} in the response.
46864 (typeof(action.result) != 'undefined') &&
46865 (typeof(action.result.errors) != 'undefined') &&
46866 (typeof(action.result.errors.needs_confirm) != 'undefined')
46869 Roo.MessageBox.confirm(
46870 "Change requires confirmation",
46871 action.result.errorMsg,
46876 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46886 Roo.callback(o.failure, o.scope, [this, action]);
46887 // show an error message if no failed handler is set..
46888 if (!this.hasListener('actionfailed')) {
46889 Roo.MessageBox.alert("Error",
46890 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46891 action.result.errorMsg :
46892 "Saving Failed, please check your entries or try again"
46896 this.fireEvent('actionfailed', this, action);
46902 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46903 * @param {String} id The value to search for
46906 findField : function(id){
46907 var field = this.items.get(id);
46909 this.items.each(function(f){
46910 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46916 return field || null;
46920 * Add a secondary form to this one,
46921 * Used to provide tabbed forms. One form is primary, with hidden values
46922 * which mirror the elements from the other forms.
46924 * @param {Roo.form.Form} form to add.
46927 addForm : function(form)
46930 if (this.childForms.indexOf(form) > -1) {
46934 this.childForms.push(form);
46936 Roo.each(form.allItems, function (fe) {
46938 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46939 if (this.findField(n)) { // already added..
46942 var add = new Roo.form.Hidden({
46945 add.render(this.el);
46952 * Mark fields in this form invalid in bulk.
46953 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46954 * @return {BasicForm} this
46956 markInvalid : function(errors){
46957 if(errors instanceof Array){
46958 for(var i = 0, len = errors.length; i < len; i++){
46959 var fieldError = errors[i];
46960 var f = this.findField(fieldError.id);
46962 f.markInvalid(fieldError.msg);
46968 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46969 field.markInvalid(errors[id]);
46973 Roo.each(this.childForms || [], function (f) {
46974 f.markInvalid(errors);
46981 * Set values for fields in this form in bulk.
46982 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46983 * @return {BasicForm} this
46985 setValues : function(values){
46986 if(values instanceof Array){ // array of objects
46987 for(var i = 0, len = values.length; i < len; i++){
46989 var f = this.findField(v.id);
46991 f.setValue(v.value);
46992 if(this.trackResetOnLoad){
46993 f.originalValue = f.getValue();
46997 }else{ // object hash
47000 if(typeof values[id] != 'function' && (field = this.findField(id))){
47002 if (field.setFromData &&
47003 field.valueField &&
47004 field.displayField &&
47005 // combos' with local stores can
47006 // be queried via setValue()
47007 // to set their value..
47008 (field.store && !field.store.isLocal)
47012 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47013 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47014 field.setFromData(sd);
47017 field.setValue(values[id]);
47021 if(this.trackResetOnLoad){
47022 field.originalValue = field.getValue();
47027 this.resetHasChanged();
47030 Roo.each(this.childForms || [], function (f) {
47031 f.setValues(values);
47032 f.resetHasChanged();
47039 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47040 * they are returned as an array.
47041 * @param {Boolean} asString
47044 getValues : function(asString){
47045 if (this.childForms) {
47046 // copy values from the child forms
47047 Roo.each(this.childForms, function (f) {
47048 this.setValues(f.getValues());
47054 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47055 if(asString === true){
47058 return Roo.urlDecode(fs);
47062 * Returns the fields in this form as an object with key/value pairs.
47063 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47066 getFieldValues : function(with_hidden)
47068 if (this.childForms) {
47069 // copy values from the child forms
47070 // should this call getFieldValues - probably not as we do not currently copy
47071 // hidden fields when we generate..
47072 Roo.each(this.childForms, function (f) {
47073 this.setValues(f.getValues());
47078 this.items.each(function(f){
47079 if (!f.getName()) {
47082 var v = f.getValue();
47083 if (f.inputType =='radio') {
47084 if (typeof(ret[f.getName()]) == 'undefined') {
47085 ret[f.getName()] = ''; // empty..
47088 if (!f.el.dom.checked) {
47092 v = f.el.dom.value;
47096 // not sure if this supported any more..
47097 if ((typeof(v) == 'object') && f.getRawValue) {
47098 v = f.getRawValue() ; // dates..
47100 // combo boxes where name != hiddenName...
47101 if (f.name != f.getName()) {
47102 ret[f.name] = f.getRawValue();
47104 ret[f.getName()] = v;
47111 * Clears all invalid messages in this form.
47112 * @return {BasicForm} this
47114 clearInvalid : function(){
47115 this.items.each(function(f){
47119 Roo.each(this.childForms || [], function (f) {
47128 * Resets this form.
47129 * @return {BasicForm} this
47131 reset : function(){
47132 this.items.each(function(f){
47136 Roo.each(this.childForms || [], function (f) {
47139 this.resetHasChanged();
47145 * Add Roo.form components to this form.
47146 * @param {Field} field1
47147 * @param {Field} field2 (optional)
47148 * @param {Field} etc (optional)
47149 * @return {BasicForm} this
47152 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47158 * Removes a field from the items collection (does NOT remove its markup).
47159 * @param {Field} field
47160 * @return {BasicForm} this
47162 remove : function(field){
47163 this.items.remove(field);
47168 * Looks at the fields in this form, checks them for an id attribute,
47169 * and calls applyTo on the existing dom element with that id.
47170 * @return {BasicForm} this
47172 render : function(){
47173 this.items.each(function(f){
47174 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47182 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47183 * @param {Object} values
47184 * @return {BasicForm} this
47186 applyToFields : function(o){
47187 this.items.each(function(f){
47194 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47195 * @param {Object} values
47196 * @return {BasicForm} this
47198 applyIfToFields : function(o){
47199 this.items.each(function(f){
47207 Roo.BasicForm = Roo.form.BasicForm;/*
47209 * Ext JS Library 1.1.1
47210 * Copyright(c) 2006-2007, Ext JS, LLC.
47212 * Originally Released Under LGPL - original licence link has changed is not relivant.
47215 * <script type="text/javascript">
47219 * @class Roo.form.Form
47220 * @extends Roo.form.BasicForm
47221 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47223 * @param {Object} config Configuration options
47225 Roo.form.Form = function(config){
47227 if (config.items) {
47228 xitems = config.items;
47229 delete config.items;
47233 Roo.form.Form.superclass.constructor.call(this, null, config);
47234 this.url = this.url || this.action;
47236 this.root = new Roo.form.Layout(Roo.applyIf({
47240 this.active = this.root;
47242 * Array of all the buttons that have been added to this form via {@link addButton}
47246 this.allItems = [];
47249 * @event clientvalidation
47250 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47251 * @param {Form} this
47252 * @param {Boolean} valid true if the form has passed client-side validation
47254 clientvalidation: true,
47257 * Fires when the form is rendered
47258 * @param {Roo.form.Form} form
47263 if (this.progressUrl) {
47264 // push a hidden field onto the list of fields..
47268 name : 'UPLOAD_IDENTIFIER'
47273 Roo.each(xitems, this.addxtype, this);
47279 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47281 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47284 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47287 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47289 buttonAlign:'center',
47292 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47297 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47298 * This property cascades to child containers if not set.
47303 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47304 * fires a looping event with that state. This is required to bind buttons to the valid
47305 * state using the config value formBind:true on the button.
47307 monitorValid : false,
47310 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47315 * @cfg {String} progressUrl - Url to return progress data
47318 progressUrl : false,
47321 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47322 * fields are added and the column is closed. If no fields are passed the column remains open
47323 * until end() is called.
47324 * @param {Object} config The config to pass to the column
47325 * @param {Field} field1 (optional)
47326 * @param {Field} field2 (optional)
47327 * @param {Field} etc (optional)
47328 * @return Column The column container object
47330 column : function(c){
47331 var col = new Roo.form.Column(c);
47333 if(arguments.length > 1){ // duplicate code required because of Opera
47334 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47341 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47342 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47343 * until end() is called.
47344 * @param {Object} config The config to pass to the fieldset
47345 * @param {Field} field1 (optional)
47346 * @param {Field} field2 (optional)
47347 * @param {Field} etc (optional)
47348 * @return FieldSet The fieldset container object
47350 fieldset : function(c){
47351 var fs = new Roo.form.FieldSet(c);
47353 if(arguments.length > 1){ // duplicate code required because of Opera
47354 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47361 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47362 * fields are added and the container is closed. If no fields are passed the container remains open
47363 * until end() is called.
47364 * @param {Object} config The config to pass to the Layout
47365 * @param {Field} field1 (optional)
47366 * @param {Field} field2 (optional)
47367 * @param {Field} etc (optional)
47368 * @return Layout The container object
47370 container : function(c){
47371 var l = new Roo.form.Layout(c);
47373 if(arguments.length > 1){ // duplicate code required because of Opera
47374 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47381 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47382 * @param {Object} container A Roo.form.Layout or subclass of Layout
47383 * @return {Form} this
47385 start : function(c){
47386 // cascade label info
47387 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47388 this.active.stack.push(c);
47389 c.ownerCt = this.active;
47395 * Closes the current open container
47396 * @return {Form} this
47399 if(this.active == this.root){
47402 this.active = this.active.ownerCt;
47407 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47408 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47409 * as the label of the field.
47410 * @param {Field} field1
47411 * @param {Field} field2 (optional)
47412 * @param {Field} etc. (optional)
47413 * @return {Form} this
47416 this.active.stack.push.apply(this.active.stack, arguments);
47417 this.allItems.push.apply(this.allItems,arguments);
47419 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47420 if(a[i].isFormField){
47425 Roo.form.Form.superclass.add.apply(this, r);
47435 * Find any element that has been added to a form, using it's ID or name
47436 * This can include framesets, columns etc. along with regular fields..
47437 * @param {String} id - id or name to find.
47439 * @return {Element} e - or false if nothing found.
47441 findbyId : function(id)
47447 Roo.each(this.allItems, function(f){
47448 if (f.id == id || f.name == id ){
47459 * Render this form into the passed container. This should only be called once!
47460 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47461 * @return {Form} this
47463 render : function(ct)
47469 var o = this.autoCreate || {
47471 method : this.method || 'POST',
47472 id : this.id || Roo.id()
47474 this.initEl(ct.createChild(o));
47476 this.root.render(this.el);
47480 this.items.each(function(f){
47481 f.render('x-form-el-'+f.id);
47484 if(this.buttons.length > 0){
47485 // tables are required to maintain order and for correct IE layout
47486 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47487 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47488 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47490 var tr = tb.getElementsByTagName('tr')[0];
47491 for(var i = 0, len = this.buttons.length; i < len; i++) {
47492 var b = this.buttons[i];
47493 var td = document.createElement('td');
47494 td.className = 'x-form-btn-td';
47495 b.render(tr.appendChild(td));
47498 if(this.monitorValid){ // initialize after render
47499 this.startMonitoring();
47501 this.fireEvent('rendered', this);
47506 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47507 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47508 * object or a valid Roo.DomHelper element config
47509 * @param {Function} handler The function called when the button is clicked
47510 * @param {Object} scope (optional) The scope of the handler function
47511 * @return {Roo.Button}
47513 addButton : function(config, handler, scope){
47517 minWidth: this.minButtonWidth,
47520 if(typeof config == "string"){
47523 Roo.apply(bc, config);
47525 var btn = new Roo.Button(null, bc);
47526 this.buttons.push(btn);
47531 * Adds a series of form elements (using the xtype property as the factory method.
47532 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47533 * @param {Object} config
47536 addxtype : function()
47538 var ar = Array.prototype.slice.call(arguments, 0);
47540 for(var i = 0; i < ar.length; i++) {
47542 continue; // skip -- if this happends something invalid got sent, we
47543 // should ignore it, as basically that interface element will not show up
47544 // and that should be pretty obvious!!
47547 if (Roo.form[ar[i].xtype]) {
47549 var fe = Roo.factory(ar[i], Roo.form);
47555 fe.store.form = this;
47560 this.allItems.push(fe);
47561 if (fe.items && fe.addxtype) {
47562 fe.addxtype.apply(fe, fe.items);
47572 // console.log('adding ' + ar[i].xtype);
47574 if (ar[i].xtype == 'Button') {
47575 //console.log('adding button');
47576 //console.log(ar[i]);
47577 this.addButton(ar[i]);
47578 this.allItems.push(fe);
47582 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47583 alert('end is not supported on xtype any more, use items');
47585 // //console.log('adding end');
47593 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47594 * option "monitorValid"
47596 startMonitoring : function(){
47599 Roo.TaskMgr.start({
47600 run : this.bindHandler,
47601 interval : this.monitorPoll || 200,
47608 * Stops monitoring of the valid state of this form
47610 stopMonitoring : function(){
47611 this.bound = false;
47615 bindHandler : function(){
47617 return false; // stops binding
47620 this.items.each(function(f){
47621 if(!f.isValid(true)){
47626 for(var i = 0, len = this.buttons.length; i < len; i++){
47627 var btn = this.buttons[i];
47628 if(btn.formBind === true && btn.disabled === valid){
47629 btn.setDisabled(!valid);
47632 this.fireEvent('clientvalidation', this, valid);
47646 Roo.Form = Roo.form.Form;
47649 * Ext JS Library 1.1.1
47650 * Copyright(c) 2006-2007, Ext JS, LLC.
47652 * Originally Released Under LGPL - original licence link has changed is not relivant.
47655 * <script type="text/javascript">
47658 // as we use this in bootstrap.
47659 Roo.namespace('Roo.form');
47661 * @class Roo.form.Action
47662 * Internal Class used to handle form actions
47664 * @param {Roo.form.BasicForm} el The form element or its id
47665 * @param {Object} config Configuration options
47670 // define the action interface
47671 Roo.form.Action = function(form, options){
47673 this.options = options || {};
47676 * Client Validation Failed
47679 Roo.form.Action.CLIENT_INVALID = 'client';
47681 * Server Validation Failed
47684 Roo.form.Action.SERVER_INVALID = 'server';
47686 * Connect to Server Failed
47689 Roo.form.Action.CONNECT_FAILURE = 'connect';
47691 * Reading Data from Server Failed
47694 Roo.form.Action.LOAD_FAILURE = 'load';
47696 Roo.form.Action.prototype = {
47698 failureType : undefined,
47699 response : undefined,
47700 result : undefined,
47702 // interface method
47703 run : function(options){
47707 // interface method
47708 success : function(response){
47712 // interface method
47713 handleResponse : function(response){
47717 // default connection failure
47718 failure : function(response){
47720 this.response = response;
47721 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47722 this.form.afterAction(this, false);
47725 processResponse : function(response){
47726 this.response = response;
47727 if(!response.responseText){
47730 this.result = this.handleResponse(response);
47731 return this.result;
47734 // utility functions used internally
47735 getUrl : function(appendParams){
47736 var url = this.options.url || this.form.url || this.form.el.dom.action;
47738 var p = this.getParams();
47740 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47746 getMethod : function(){
47747 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47750 getParams : function(){
47751 var bp = this.form.baseParams;
47752 var p = this.options.params;
47754 if(typeof p == "object"){
47755 p = Roo.urlEncode(Roo.applyIf(p, bp));
47756 }else if(typeof p == 'string' && bp){
47757 p += '&' + Roo.urlEncode(bp);
47760 p = Roo.urlEncode(bp);
47765 createCallback : function(){
47767 success: this.success,
47768 failure: this.failure,
47770 timeout: (this.form.timeout*1000),
47771 upload: this.form.fileUpload ? this.success : undefined
47776 Roo.form.Action.Submit = function(form, options){
47777 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47780 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47783 haveProgress : false,
47784 uploadComplete : false,
47786 // uploadProgress indicator.
47787 uploadProgress : function()
47789 if (!this.form.progressUrl) {
47793 if (!this.haveProgress) {
47794 Roo.MessageBox.progress("Uploading", "Uploading");
47796 if (this.uploadComplete) {
47797 Roo.MessageBox.hide();
47801 this.haveProgress = true;
47803 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47805 var c = new Roo.data.Connection();
47807 url : this.form.progressUrl,
47812 success : function(req){
47813 //console.log(data);
47817 rdata = Roo.decode(req.responseText)
47819 Roo.log("Invalid data from server..");
47823 if (!rdata || !rdata.success) {
47825 Roo.MessageBox.alert(Roo.encode(rdata));
47828 var data = rdata.data;
47830 if (this.uploadComplete) {
47831 Roo.MessageBox.hide();
47836 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47837 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47840 this.uploadProgress.defer(2000,this);
47843 failure: function(data) {
47844 Roo.log('progress url failed ');
47855 // run get Values on the form, so it syncs any secondary forms.
47856 this.form.getValues();
47858 var o = this.options;
47859 var method = this.getMethod();
47860 var isPost = method == 'POST';
47861 if(o.clientValidation === false || this.form.isValid()){
47863 if (this.form.progressUrl) {
47864 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47865 (new Date() * 1) + '' + Math.random());
47870 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47871 form:this.form.el.dom,
47872 url:this.getUrl(!isPost),
47874 params:isPost ? this.getParams() : null,
47875 isUpload: this.form.fileUpload
47878 this.uploadProgress();
47880 }else if (o.clientValidation !== false){ // client validation failed
47881 this.failureType = Roo.form.Action.CLIENT_INVALID;
47882 this.form.afterAction(this, false);
47886 success : function(response)
47888 this.uploadComplete= true;
47889 if (this.haveProgress) {
47890 Roo.MessageBox.hide();
47894 var result = this.processResponse(response);
47895 if(result === true || result.success){
47896 this.form.afterAction(this, true);
47900 this.form.markInvalid(result.errors);
47901 this.failureType = Roo.form.Action.SERVER_INVALID;
47903 this.form.afterAction(this, false);
47905 failure : function(response)
47907 this.uploadComplete= true;
47908 if (this.haveProgress) {
47909 Roo.MessageBox.hide();
47912 this.response = response;
47913 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47914 this.form.afterAction(this, false);
47917 handleResponse : function(response){
47918 if(this.form.errorReader){
47919 var rs = this.form.errorReader.read(response);
47922 for(var i = 0, len = rs.records.length; i < len; i++) {
47923 var r = rs.records[i];
47924 errors[i] = r.data;
47927 if(errors.length < 1){
47931 success : rs.success,
47937 ret = Roo.decode(response.responseText);
47941 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47951 Roo.form.Action.Load = function(form, options){
47952 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47953 this.reader = this.form.reader;
47956 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47961 Roo.Ajax.request(Roo.apply(
47962 this.createCallback(), {
47963 method:this.getMethod(),
47964 url:this.getUrl(false),
47965 params:this.getParams()
47969 success : function(response){
47971 var result = this.processResponse(response);
47972 if(result === true || !result.success || !result.data){
47973 this.failureType = Roo.form.Action.LOAD_FAILURE;
47974 this.form.afterAction(this, false);
47977 this.form.clearInvalid();
47978 this.form.setValues(result.data);
47979 this.form.afterAction(this, true);
47982 handleResponse : function(response){
47983 if(this.form.reader){
47984 var rs = this.form.reader.read(response);
47985 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47987 success : rs.success,
47991 return Roo.decode(response.responseText);
47995 Roo.form.Action.ACTION_TYPES = {
47996 'load' : Roo.form.Action.Load,
47997 'submit' : Roo.form.Action.Submit
48000 * Ext JS Library 1.1.1
48001 * Copyright(c) 2006-2007, Ext JS, LLC.
48003 * Originally Released Under LGPL - original licence link has changed is not relivant.
48006 * <script type="text/javascript">
48010 * @class Roo.form.Layout
48011 * @extends Roo.Component
48012 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48014 * @param {Object} config Configuration options
48016 Roo.form.Layout = function(config){
48018 if (config.items) {
48019 xitems = config.items;
48020 delete config.items;
48022 Roo.form.Layout.superclass.constructor.call(this, config);
48024 Roo.each(xitems, this.addxtype, this);
48028 Roo.extend(Roo.form.Layout, Roo.Component, {
48030 * @cfg {String/Object} autoCreate
48031 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48034 * @cfg {String/Object/Function} style
48035 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48036 * a function which returns such a specification.
48039 * @cfg {String} labelAlign
48040 * Valid values are "left," "top" and "right" (defaults to "left")
48043 * @cfg {Number} labelWidth
48044 * Fixed width in pixels of all field labels (defaults to undefined)
48047 * @cfg {Boolean} clear
48048 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48052 * @cfg {String} labelSeparator
48053 * The separator to use after field labels (defaults to ':')
48055 labelSeparator : ':',
48057 * @cfg {Boolean} hideLabels
48058 * True to suppress the display of field labels in this layout (defaults to false)
48060 hideLabels : false,
48063 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48068 onRender : function(ct, position){
48069 if(this.el){ // from markup
48070 this.el = Roo.get(this.el);
48071 }else { // generate
48072 var cfg = this.getAutoCreate();
48073 this.el = ct.createChild(cfg, position);
48076 this.el.applyStyles(this.style);
48078 if(this.labelAlign){
48079 this.el.addClass('x-form-label-'+this.labelAlign);
48081 if(this.hideLabels){
48082 this.labelStyle = "display:none";
48083 this.elementStyle = "padding-left:0;";
48085 if(typeof this.labelWidth == 'number'){
48086 this.labelStyle = "width:"+this.labelWidth+"px;";
48087 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48089 if(this.labelAlign == 'top'){
48090 this.labelStyle = "width:auto;";
48091 this.elementStyle = "padding-left:0;";
48094 var stack = this.stack;
48095 var slen = stack.length;
48097 if(!this.fieldTpl){
48098 var t = new Roo.Template(
48099 '<div class="x-form-item {5}">',
48100 '<label for="{0}" style="{2}">{1}{4}</label>',
48101 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48103 '</div><div class="x-form-clear-left"></div>'
48105 t.disableFormats = true;
48107 Roo.form.Layout.prototype.fieldTpl = t;
48109 for(var i = 0; i < slen; i++) {
48110 if(stack[i].isFormField){
48111 this.renderField(stack[i]);
48113 this.renderComponent(stack[i]);
48118 this.el.createChild({cls:'x-form-clear'});
48123 renderField : function(f){
48124 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48127 f.labelStyle||this.labelStyle||'', //2
48128 this.elementStyle||'', //3
48129 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48130 f.itemCls||this.itemCls||'' //5
48131 ], true).getPrevSibling());
48135 renderComponent : function(c){
48136 c.render(c.isLayout ? this.el : this.el.createChild());
48139 * Adds a object form elements (using the xtype property as the factory method.)
48140 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48141 * @param {Object} config
48143 addxtype : function(o)
48145 // create the lement.
48146 o.form = this.form;
48147 var fe = Roo.factory(o, Roo.form);
48148 this.form.allItems.push(fe);
48149 this.stack.push(fe);
48151 if (fe.isFormField) {
48152 this.form.items.add(fe);
48160 * @class Roo.form.Column
48161 * @extends Roo.form.Layout
48162 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48164 * @param {Object} config Configuration options
48166 Roo.form.Column = function(config){
48167 Roo.form.Column.superclass.constructor.call(this, config);
48170 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48172 * @cfg {Number/String} width
48173 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48176 * @cfg {String/Object} autoCreate
48177 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48181 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48184 onRender : function(ct, position){
48185 Roo.form.Column.superclass.onRender.call(this, ct, position);
48187 this.el.setWidth(this.width);
48194 * @class Roo.form.Row
48195 * @extends Roo.form.Layout
48196 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48198 * @param {Object} config Configuration options
48202 Roo.form.Row = function(config){
48203 Roo.form.Row.superclass.constructor.call(this, config);
48206 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48208 * @cfg {Number/String} width
48209 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48212 * @cfg {Number/String} height
48213 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48215 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48219 onRender : function(ct, position){
48220 //console.log('row render');
48222 var t = new Roo.Template(
48223 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48224 '<label for="{0}" style="{2}">{1}{4}</label>',
48225 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48229 t.disableFormats = true;
48231 Roo.form.Layout.prototype.rowTpl = t;
48233 this.fieldTpl = this.rowTpl;
48235 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48236 var labelWidth = 100;
48238 if ((this.labelAlign != 'top')) {
48239 if (typeof this.labelWidth == 'number') {
48240 labelWidth = this.labelWidth
48242 this.padWidth = 20 + labelWidth;
48246 Roo.form.Column.superclass.onRender.call(this, ct, position);
48248 this.el.setWidth(this.width);
48251 this.el.setHeight(this.height);
48256 renderField : function(f){
48257 f.fieldEl = this.fieldTpl.append(this.el, [
48258 f.id, f.fieldLabel,
48259 f.labelStyle||this.labelStyle||'',
48260 this.elementStyle||'',
48261 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48262 f.itemCls||this.itemCls||'',
48263 f.width ? f.width + this.padWidth : 160 + this.padWidth
48270 * @class Roo.form.FieldSet
48271 * @extends Roo.form.Layout
48272 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48274 * @param {Object} config Configuration options
48276 Roo.form.FieldSet = function(config){
48277 Roo.form.FieldSet.superclass.constructor.call(this, config);
48280 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48282 * @cfg {String} legend
48283 * The text to display as the legend for the FieldSet (defaults to '')
48286 * @cfg {String/Object} autoCreate
48287 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48291 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48294 onRender : function(ct, position){
48295 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48297 this.setLegend(this.legend);
48302 setLegend : function(text){
48304 this.el.child('legend').update(text);
48309 * Ext JS Library 1.1.1
48310 * Copyright(c) 2006-2007, Ext JS, LLC.
48312 * Originally Released Under LGPL - original licence link has changed is not relivant.
48315 * <script type="text/javascript">
48318 * @class Roo.form.VTypes
48319 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48322 Roo.form.VTypes = function(){
48323 // closure these in so they are only created once.
48324 var alpha = /^[a-zA-Z_]+$/;
48325 var alphanum = /^[a-zA-Z0-9_]+$/;
48326 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48327 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48329 // All these messages and functions are configurable
48332 * The function used to validate email addresses
48333 * @param {String} value The email address
48335 'email' : function(v){
48336 return email.test(v);
48339 * The error text to display when the email validation function returns false
48342 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48344 * The keystroke filter mask to be applied on email input
48347 'emailMask' : /[a-z0-9_\.\-@]/i,
48350 * The function used to validate URLs
48351 * @param {String} value The URL
48353 'url' : function(v){
48354 return url.test(v);
48357 * The error text to display when the url validation function returns false
48360 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48363 * The function used to validate alpha values
48364 * @param {String} value The value
48366 'alpha' : function(v){
48367 return alpha.test(v);
48370 * The error text to display when the alpha validation function returns false
48373 'alphaText' : 'This field should only contain letters and _',
48375 * The keystroke filter mask to be applied on alpha input
48378 'alphaMask' : /[a-z_]/i,
48381 * The function used to validate alphanumeric values
48382 * @param {String} value The value
48384 'alphanum' : function(v){
48385 return alphanum.test(v);
48388 * The error text to display when the alphanumeric validation function returns false
48391 'alphanumText' : 'This field should only contain letters, numbers and _',
48393 * The keystroke filter mask to be applied on alphanumeric input
48396 'alphanumMask' : /[a-z0-9_]/i
48398 }();//<script type="text/javascript">
48401 * @class Roo.form.FCKeditor
48402 * @extends Roo.form.TextArea
48403 * Wrapper around the FCKEditor http://www.fckeditor.net
48405 * Creates a new FCKeditor
48406 * @param {Object} config Configuration options
48408 Roo.form.FCKeditor = function(config){
48409 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48412 * @event editorinit
48413 * Fired when the editor is initialized - you can add extra handlers here..
48414 * @param {FCKeditor} this
48415 * @param {Object} the FCK object.
48422 Roo.form.FCKeditor.editors = { };
48423 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48425 //defaultAutoCreate : {
48426 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48430 * @cfg {Object} fck options - see fck manual for details.
48435 * @cfg {Object} fck toolbar set (Basic or Default)
48437 toolbarSet : 'Basic',
48439 * @cfg {Object} fck BasePath
48441 basePath : '/fckeditor/',
48449 onRender : function(ct, position)
48452 this.defaultAutoCreate = {
48454 style:"width:300px;height:60px;",
48455 autocomplete: "new-password"
48458 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48461 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48462 if(this.preventScrollbars){
48463 this.el.setStyle("overflow", "hidden");
48465 this.el.setHeight(this.growMin);
48468 //console.log('onrender' + this.getId() );
48469 Roo.form.FCKeditor.editors[this.getId()] = this;
48472 this.replaceTextarea() ;
48476 getEditor : function() {
48477 return this.fckEditor;
48480 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48481 * @param {Mixed} value The value to set
48485 setValue : function(value)
48487 //console.log('setValue: ' + value);
48489 if(typeof(value) == 'undefined') { // not sure why this is happending...
48492 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48494 //if(!this.el || !this.getEditor()) {
48495 // this.value = value;
48496 //this.setValue.defer(100,this,[value]);
48500 if(!this.getEditor()) {
48504 this.getEditor().SetData(value);
48511 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48512 * @return {Mixed} value The field value
48514 getValue : function()
48517 if (this.frame && this.frame.dom.style.display == 'none') {
48518 return Roo.form.FCKeditor.superclass.getValue.call(this);
48521 if(!this.el || !this.getEditor()) {
48523 // this.getValue.defer(100,this);
48528 var value=this.getEditor().GetData();
48529 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48530 return Roo.form.FCKeditor.superclass.getValue.call(this);
48536 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48537 * @return {Mixed} value The field value
48539 getRawValue : function()
48541 if (this.frame && this.frame.dom.style.display == 'none') {
48542 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48545 if(!this.el || !this.getEditor()) {
48546 //this.getRawValue.defer(100,this);
48553 var value=this.getEditor().GetData();
48554 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48555 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48559 setSize : function(w,h) {
48563 //if (this.frame && this.frame.dom.style.display == 'none') {
48564 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48567 //if(!this.el || !this.getEditor()) {
48568 // this.setSize.defer(100,this, [w,h]);
48574 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48576 this.frame.dom.setAttribute('width', w);
48577 this.frame.dom.setAttribute('height', h);
48578 this.frame.setSize(w,h);
48582 toggleSourceEdit : function(value) {
48586 this.el.dom.style.display = value ? '' : 'none';
48587 this.frame.dom.style.display = value ? 'none' : '';
48592 focus: function(tag)
48594 if (this.frame.dom.style.display == 'none') {
48595 return Roo.form.FCKeditor.superclass.focus.call(this);
48597 if(!this.el || !this.getEditor()) {
48598 this.focus.defer(100,this, [tag]);
48605 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48606 this.getEditor().Focus();
48608 if (!this.getEditor().Selection.GetSelection()) {
48609 this.focus.defer(100,this, [tag]);
48614 var r = this.getEditor().EditorDocument.createRange();
48615 r.setStart(tgs[0],0);
48616 r.setEnd(tgs[0],0);
48617 this.getEditor().Selection.GetSelection().removeAllRanges();
48618 this.getEditor().Selection.GetSelection().addRange(r);
48619 this.getEditor().Focus();
48626 replaceTextarea : function()
48628 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48631 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48633 // We must check the elements firstly using the Id and then the name.
48634 var oTextarea = document.getElementById( this.getId() );
48636 var colElementsByName = document.getElementsByName( this.getId() ) ;
48638 oTextarea.style.display = 'none' ;
48640 if ( oTextarea.tabIndex ) {
48641 this.TabIndex = oTextarea.tabIndex ;
48644 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48645 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48646 this.frame = Roo.get(this.getId() + '___Frame')
48649 _getConfigHtml : function()
48653 for ( var o in this.fckconfig ) {
48654 sConfig += sConfig.length > 0 ? '&' : '';
48655 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48658 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48662 _getIFrameHtml : function()
48664 var sFile = 'fckeditor.html' ;
48665 /* no idea what this is about..
48668 if ( (/fcksource=true/i).test( window.top.location.search ) )
48669 sFile = 'fckeditor.original.html' ;
48674 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48675 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48678 var html = '<iframe id="' + this.getId() +
48679 '___Frame" src="' + sLink +
48680 '" width="' + this.width +
48681 '" height="' + this.height + '"' +
48682 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48683 ' frameborder="0" scrolling="no"></iframe>' ;
48688 _insertHtmlBefore : function( html, element )
48690 if ( element.insertAdjacentHTML ) {
48692 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48694 var oRange = document.createRange() ;
48695 oRange.setStartBefore( element ) ;
48696 var oFragment = oRange.createContextualFragment( html );
48697 element.parentNode.insertBefore( oFragment, element ) ;
48710 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48712 function FCKeditor_OnComplete(editorInstance){
48713 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48714 f.fckEditor = editorInstance;
48715 //console.log("loaded");
48716 f.fireEvent('editorinit', f, editorInstance);
48736 //<script type="text/javascript">
48738 * @class Roo.form.GridField
48739 * @extends Roo.form.Field
48740 * Embed a grid (or editable grid into a form)
48743 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48745 * xgrid.store = Roo.data.Store
48746 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48747 * xgrid.store.reader = Roo.data.JsonReader
48751 * Creates a new GridField
48752 * @param {Object} config Configuration options
48754 Roo.form.GridField = function(config){
48755 Roo.form.GridField.superclass.constructor.call(this, config);
48759 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48761 * @cfg {Number} width - used to restrict width of grid..
48765 * @cfg {Number} height - used to restrict height of grid..
48769 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48775 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48776 * {tag: "input", type: "checkbox", autocomplete: "off"})
48778 // defaultAutoCreate : { tag: 'div' },
48779 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48781 * @cfg {String} addTitle Text to include for adding a title.
48785 onResize : function(){
48786 Roo.form.Field.superclass.onResize.apply(this, arguments);
48789 initEvents : function(){
48790 // Roo.form.Checkbox.superclass.initEvents.call(this);
48791 // has no events...
48796 getResizeEl : function(){
48800 getPositionEl : function(){
48805 onRender : function(ct, position){
48807 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48808 var style = this.style;
48811 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48812 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48813 this.viewEl = this.wrap.createChild({ tag: 'div' });
48815 this.viewEl.applyStyles(style);
48818 this.viewEl.setWidth(this.width);
48821 this.viewEl.setHeight(this.height);
48823 //if(this.inputValue !== undefined){
48824 //this.setValue(this.value);
48827 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48830 this.grid.render();
48831 this.grid.getDataSource().on('remove', this.refreshValue, this);
48832 this.grid.getDataSource().on('update', this.refreshValue, this);
48833 this.grid.on('afteredit', this.refreshValue, this);
48839 * Sets the value of the item.
48840 * @param {String} either an object or a string..
48842 setValue : function(v){
48844 v = v || []; // empty set..
48845 // this does not seem smart - it really only affects memoryproxy grids..
48846 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48847 var ds = this.grid.getDataSource();
48848 // assumes a json reader..
48850 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48851 ds.loadData( data);
48853 // clear selection so it does not get stale.
48854 if (this.grid.sm) {
48855 this.grid.sm.clearSelections();
48858 Roo.form.GridField.superclass.setValue.call(this, v);
48859 this.refreshValue();
48860 // should load data in the grid really....
48864 refreshValue: function() {
48866 this.grid.getDataSource().each(function(r) {
48869 this.el.dom.value = Roo.encode(val);
48877 * Ext JS Library 1.1.1
48878 * Copyright(c) 2006-2007, Ext JS, LLC.
48880 * Originally Released Under LGPL - original licence link has changed is not relivant.
48883 * <script type="text/javascript">
48886 * @class Roo.form.DisplayField
48887 * @extends Roo.form.Field
48888 * A generic Field to display non-editable data.
48889 * @cfg {Boolean} closable (true|false) default false
48891 * Creates a new Display Field item.
48892 * @param {Object} config Configuration options
48894 Roo.form.DisplayField = function(config){
48895 Roo.form.DisplayField.superclass.constructor.call(this, config);
48900 * Fires after the click the close btn
48901 * @param {Roo.form.DisplayField} this
48907 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48908 inputType: 'hidden',
48914 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48916 focusClass : undefined,
48918 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48920 fieldClass: 'x-form-field',
48923 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48925 valueRenderer: undefined,
48929 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48930 * {tag: "input", type: "checkbox", autocomplete: "off"})
48933 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48937 onResize : function(){
48938 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48942 initEvents : function(){
48943 // Roo.form.Checkbox.superclass.initEvents.call(this);
48944 // has no events...
48947 this.closeEl.on('click', this.onClose, this);
48953 getResizeEl : function(){
48957 getPositionEl : function(){
48962 onRender : function(ct, position){
48964 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48965 //if(this.inputValue !== undefined){
48966 this.wrap = this.el.wrap();
48968 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48971 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48974 if (this.bodyStyle) {
48975 this.viewEl.applyStyles(this.bodyStyle);
48977 //this.viewEl.setStyle('padding', '2px');
48979 this.setValue(this.value);
48984 initValue : Roo.emptyFn,
48989 onClick : function(){
48994 * Sets the checked state of the checkbox.
48995 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48997 setValue : function(v){
48999 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49000 // this might be called before we have a dom element..
49001 if (!this.viewEl) {
49004 this.viewEl.dom.innerHTML = html;
49005 Roo.form.DisplayField.superclass.setValue.call(this, v);
49009 onClose : function(e)
49011 e.preventDefault();
49013 this.fireEvent('close', this);
49022 * @class Roo.form.DayPicker
49023 * @extends Roo.form.Field
49024 * A Day picker show [M] [T] [W] ....
49026 * Creates a new Day Picker
49027 * @param {Object} config Configuration options
49029 Roo.form.DayPicker= function(config){
49030 Roo.form.DayPicker.superclass.constructor.call(this, config);
49034 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49036 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49038 focusClass : undefined,
49040 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49042 fieldClass: "x-form-field",
49045 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49046 * {tag: "input", type: "checkbox", autocomplete: "off"})
49048 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49051 actionMode : 'viewEl',
49055 inputType : 'hidden',
49058 inputElement: false, // real input element?
49059 basedOn: false, // ????
49061 isFormField: true, // not sure where this is needed!!!!
49063 onResize : function(){
49064 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49065 if(!this.boxLabel){
49066 this.el.alignTo(this.wrap, 'c-c');
49070 initEvents : function(){
49071 Roo.form.Checkbox.superclass.initEvents.call(this);
49072 this.el.on("click", this.onClick, this);
49073 this.el.on("change", this.onClick, this);
49077 getResizeEl : function(){
49081 getPositionEl : function(){
49087 onRender : function(ct, position){
49088 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49090 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49092 var r1 = '<table><tr>';
49093 var r2 = '<tr class="x-form-daypick-icons">';
49094 for (var i=0; i < 7; i++) {
49095 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49096 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49099 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49100 viewEl.select('img').on('click', this.onClick, this);
49101 this.viewEl = viewEl;
49104 // this will not work on Chrome!!!
49105 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49106 this.el.on('propertychange', this.setFromHidden, this); //ie
49114 initValue : Roo.emptyFn,
49117 * Returns the checked state of the checkbox.
49118 * @return {Boolean} True if checked, else false
49120 getValue : function(){
49121 return this.el.dom.value;
49126 onClick : function(e){
49127 //this.setChecked(!this.checked);
49128 Roo.get(e.target).toggleClass('x-menu-item-checked');
49129 this.refreshValue();
49130 //if(this.el.dom.checked != this.checked){
49131 // this.setValue(this.el.dom.checked);
49136 refreshValue : function()
49139 this.viewEl.select('img',true).each(function(e,i,n) {
49140 val += e.is(".x-menu-item-checked") ? String(n) : '';
49142 this.setValue(val, true);
49146 * Sets the checked state of the checkbox.
49147 * On is always based on a string comparison between inputValue and the param.
49148 * @param {Boolean/String} value - the value to set
49149 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49151 setValue : function(v,suppressEvent){
49152 if (!this.el.dom) {
49155 var old = this.el.dom.value ;
49156 this.el.dom.value = v;
49157 if (suppressEvent) {
49161 // update display..
49162 this.viewEl.select('img',true).each(function(e,i,n) {
49164 var on = e.is(".x-menu-item-checked");
49165 var newv = v.indexOf(String(n)) > -1;
49167 e.toggleClass('x-menu-item-checked');
49173 this.fireEvent('change', this, v, old);
49178 // handle setting of hidden value by some other method!!?!?
49179 setFromHidden: function()
49184 //console.log("SET FROM HIDDEN");
49185 //alert('setFrom hidden');
49186 this.setValue(this.el.dom.value);
49189 onDestroy : function()
49192 Roo.get(this.viewEl).remove();
49195 Roo.form.DayPicker.superclass.onDestroy.call(this);
49199 * RooJS Library 1.1.1
49200 * Copyright(c) 2008-2011 Alan Knowles
49207 * @class Roo.form.ComboCheck
49208 * @extends Roo.form.ComboBox
49209 * A combobox for multiple select items.
49211 * FIXME - could do with a reset button..
49214 * Create a new ComboCheck
49215 * @param {Object} config Configuration options
49217 Roo.form.ComboCheck = function(config){
49218 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49219 // should verify some data...
49221 // hiddenName = required..
49222 // displayField = required
49223 // valudField == required
49224 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49226 Roo.each(req, function(e) {
49227 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49228 throw "Roo.form.ComboCheck : missing value for: " + e;
49235 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49240 selectedClass: 'x-menu-item-checked',
49243 onRender : function(ct, position){
49249 var cls = 'x-combo-list';
49252 this.tpl = new Roo.Template({
49253 html : '<div class="'+cls+'-item x-menu-check-item">' +
49254 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49255 '<span>{' + this.displayField + '}</span>' +
49262 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49263 this.view.singleSelect = false;
49264 this.view.multiSelect = true;
49265 this.view.toggleSelect = true;
49266 this.pageTb.add(new Roo.Toolbar.Fill(), {
49269 handler: function()
49276 onViewOver : function(e, t){
49282 onViewClick : function(doFocus,index){
49286 select: function () {
49287 //Roo.log("SELECT CALLED");
49290 selectByValue : function(xv, scrollIntoView){
49291 var ar = this.getValueArray();
49294 Roo.each(ar, function(v) {
49295 if(v === undefined || v === null){
49298 var r = this.findRecord(this.valueField, v);
49300 sels.push(this.store.indexOf(r))
49304 this.view.select(sels);
49310 onSelect : function(record, index){
49311 // Roo.log("onselect Called");
49312 // this is only called by the clear button now..
49313 this.view.clearSelections();
49314 this.setValue('[]');
49315 if (this.value != this.valueBefore) {
49316 this.fireEvent('change', this, this.value, this.valueBefore);
49317 this.valueBefore = this.value;
49320 getValueArray : function()
49325 //Roo.log(this.value);
49326 if (typeof(this.value) == 'undefined') {
49329 var ar = Roo.decode(this.value);
49330 return ar instanceof Array ? ar : []; //?? valid?
49333 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49338 expand : function ()
49341 Roo.form.ComboCheck.superclass.expand.call(this);
49342 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49343 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49348 collapse : function(){
49349 Roo.form.ComboCheck.superclass.collapse.call(this);
49350 var sl = this.view.getSelectedIndexes();
49351 var st = this.store;
49355 Roo.each(sl, function(i) {
49357 nv.push(r.get(this.valueField));
49359 this.setValue(Roo.encode(nv));
49360 if (this.value != this.valueBefore) {
49362 this.fireEvent('change', this, this.value, this.valueBefore);
49363 this.valueBefore = this.value;
49368 setValue : function(v){
49372 var vals = this.getValueArray();
49374 Roo.each(vals, function(k) {
49375 var r = this.findRecord(this.valueField, k);
49377 tv.push(r.data[this.displayField]);
49378 }else if(this.valueNotFoundText !== undefined){
49379 tv.push( this.valueNotFoundText );
49384 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49385 this.hiddenField.value = v;
49391 * Ext JS Library 1.1.1
49392 * Copyright(c) 2006-2007, Ext JS, LLC.
49394 * Originally Released Under LGPL - original licence link has changed is not relivant.
49397 * <script type="text/javascript">
49401 * @class Roo.form.Signature
49402 * @extends Roo.form.Field
49406 * @param {Object} config Configuration options
49409 Roo.form.Signature = function(config){
49410 Roo.form.Signature.superclass.constructor.call(this, config);
49412 this.addEvents({// not in used??
49415 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49416 * @param {Roo.form.Signature} combo This combo box
49421 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49422 * @param {Roo.form.ComboBox} combo This combo box
49423 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49429 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49431 * @cfg {Object} labels Label to use when rendering a form.
49435 * confirm : "Confirm"
49440 confirm : "Confirm"
49443 * @cfg {Number} width The signature panel width (defaults to 300)
49447 * @cfg {Number} height The signature panel height (defaults to 100)
49451 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49453 allowBlank : false,
49456 // {Object} signPanel The signature SVG panel element (defaults to {})
49458 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49459 isMouseDown : false,
49460 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49461 isConfirmed : false,
49462 // {String} signatureTmp SVG mapping string (defaults to empty string)
49466 defaultAutoCreate : { // modified by initCompnoent..
49472 onRender : function(ct, position){
49474 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49476 this.wrap = this.el.wrap({
49477 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49480 this.createToolbar(this);
49481 this.signPanel = this.wrap.createChild({
49483 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49487 this.svgID = Roo.id();
49488 this.svgEl = this.signPanel.createChild({
49489 xmlns : 'http://www.w3.org/2000/svg',
49491 id : this.svgID + "-svg",
49493 height: this.height,
49494 viewBox: '0 0 '+this.width+' '+this.height,
49498 id: this.svgID + "-svg-r",
49500 height: this.height,
49505 id: this.svgID + "-svg-l",
49507 y1: (this.height*0.8), // start set the line in 80% of height
49508 x2: this.width, // end
49509 y2: (this.height*0.8), // end set the line in 80% of height
49511 'stroke-width': "1",
49512 'stroke-dasharray': "3",
49513 'shape-rendering': "crispEdges",
49514 'pointer-events': "none"
49518 id: this.svgID + "-svg-p",
49520 'stroke-width': "3",
49522 'pointer-events': 'none'
49527 this.svgBox = this.svgEl.dom.getScreenCTM();
49529 createSVG : function(){
49530 var svg = this.signPanel;
49531 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49534 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49535 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49536 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49537 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49538 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49539 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49540 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49543 isTouchEvent : function(e){
49544 return e.type.match(/^touch/);
49546 getCoords : function (e) {
49547 var pt = this.svgEl.dom.createSVGPoint();
49550 if (this.isTouchEvent(e)) {
49551 pt.x = e.targetTouches[0].clientX;
49552 pt.y = e.targetTouches[0].clientY;
49554 var a = this.svgEl.dom.getScreenCTM();
49555 var b = a.inverse();
49556 var mx = pt.matrixTransform(b);
49557 return mx.x + ',' + mx.y;
49559 //mouse event headler
49560 down : function (e) {
49561 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49562 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49564 this.isMouseDown = true;
49566 e.preventDefault();
49568 move : function (e) {
49569 if (this.isMouseDown) {
49570 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49571 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49574 e.preventDefault();
49576 up : function (e) {
49577 this.isMouseDown = false;
49578 var sp = this.signatureTmp.split(' ');
49581 if(!sp[sp.length-2].match(/^L/)){
49585 this.signatureTmp = sp.join(" ");
49588 if(this.getValue() != this.signatureTmp){
49589 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49590 this.isConfirmed = false;
49592 e.preventDefault();
49596 * Protected method that will not generally be called directly. It
49597 * is called when the editor creates its toolbar. Override this method if you need to
49598 * add custom toolbar buttons.
49599 * @param {HtmlEditor} editor
49601 createToolbar : function(editor){
49602 function btn(id, toggle, handler){
49603 var xid = fid + '-'+ id ;
49607 cls : 'x-btn-icon x-edit-'+id,
49608 enableToggle:toggle !== false,
49609 scope: editor, // was editor...
49610 handler:handler||editor.relayBtnCmd,
49611 clickEvent:'mousedown',
49612 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49618 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49622 cls : ' x-signature-btn x-signature-'+id,
49623 scope: editor, // was editor...
49624 handler: this.reset,
49625 clickEvent:'mousedown',
49626 text: this.labels.clear
49633 cls : ' x-signature-btn x-signature-'+id,
49634 scope: editor, // was editor...
49635 handler: this.confirmHandler,
49636 clickEvent:'mousedown',
49637 text: this.labels.confirm
49644 * when user is clicked confirm then show this image.....
49646 * @return {String} Image Data URI
49648 getImageDataURI : function(){
49649 var svg = this.svgEl.dom.parentNode.innerHTML;
49650 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49655 * @return {Boolean} this.isConfirmed
49657 getConfirmed : function(){
49658 return this.isConfirmed;
49662 * @return {Number} this.width
49664 getWidth : function(){
49669 * @return {Number} this.height
49671 getHeight : function(){
49672 return this.height;
49675 getSignature : function(){
49676 return this.signatureTmp;
49679 reset : function(){
49680 this.signatureTmp = '';
49681 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49682 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49683 this.isConfirmed = false;
49684 Roo.form.Signature.superclass.reset.call(this);
49686 setSignature : function(s){
49687 this.signatureTmp = s;
49688 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49689 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49691 this.isConfirmed = false;
49692 Roo.form.Signature.superclass.reset.call(this);
49695 // Roo.log(this.signPanel.dom.contentWindow.up())
49698 setConfirmed : function(){
49702 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49705 confirmHandler : function(){
49706 if(!this.getSignature()){
49710 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49711 this.setValue(this.getSignature());
49712 this.isConfirmed = true;
49714 this.fireEvent('confirm', this);
49717 // Subclasses should provide the validation implementation by overriding this
49718 validateValue : function(value){
49719 if(this.allowBlank){
49723 if(this.isConfirmed){
49730 * Ext JS Library 1.1.1
49731 * Copyright(c) 2006-2007, Ext JS, LLC.
49733 * Originally Released Under LGPL - original licence link has changed is not relivant.
49736 * <script type="text/javascript">
49741 * @class Roo.form.ComboBox
49742 * @extends Roo.form.TriggerField
49743 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49745 * Create a new ComboBox.
49746 * @param {Object} config Configuration options
49748 Roo.form.Select = function(config){
49749 Roo.form.Select.superclass.constructor.call(this, config);
49753 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49755 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49758 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49759 * rendering into an Roo.Editor, defaults to false)
49762 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49763 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49766 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49769 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49770 * the dropdown list (defaults to undefined, with no header element)
49774 * @cfg {String/Roo.Template} tpl The template to use to render the output
49778 defaultAutoCreate : {tag: "select" },
49780 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49782 listWidth: undefined,
49784 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49785 * mode = 'remote' or 'text' if mode = 'local')
49787 displayField: undefined,
49789 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49790 * mode = 'remote' or 'value' if mode = 'local').
49791 * Note: use of a valueField requires the user make a selection
49792 * in order for a value to be mapped.
49794 valueField: undefined,
49798 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49799 * field's data value (defaults to the underlying DOM element's name)
49801 hiddenName: undefined,
49803 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49807 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49809 selectedClass: 'x-combo-selected',
49811 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49812 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49813 * which displays a downward arrow icon).
49815 triggerClass : 'x-form-arrow-trigger',
49817 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49821 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49822 * anchor positions (defaults to 'tl-bl')
49824 listAlign: 'tl-bl?',
49826 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49830 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49831 * query specified by the allQuery config option (defaults to 'query')
49833 triggerAction: 'query',
49835 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49836 * (defaults to 4, does not apply if editable = false)
49840 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49841 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49845 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49846 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49850 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49851 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49855 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49856 * when editable = true (defaults to false)
49858 selectOnFocus:false,
49860 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49862 queryParam: 'query',
49864 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49865 * when mode = 'remote' (defaults to 'Loading...')
49867 loadingText: 'Loading...',
49869 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49873 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49877 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49878 * traditional select (defaults to true)
49882 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49886 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49890 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49891 * listWidth has a higher value)
49895 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49896 * allow the user to set arbitrary text into the field (defaults to false)
49898 forceSelection:false,
49900 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49901 * if typeAhead = true (defaults to 250)
49903 typeAheadDelay : 250,
49905 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49906 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49908 valueNotFoundText : undefined,
49911 * @cfg {String} defaultValue The value displayed after loading the store.
49916 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49918 blockFocus : false,
49921 * @cfg {Boolean} disableClear Disable showing of clear button.
49923 disableClear : false,
49925 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49927 alwaysQuery : false,
49933 // element that contains real text value.. (when hidden is used..)
49936 onRender : function(ct, position){
49937 Roo.form.Field.prototype.onRender.call(this, ct, position);
49940 this.store.on('beforeload', this.onBeforeLoad, this);
49941 this.store.on('load', this.onLoad, this);
49942 this.store.on('loadexception', this.onLoadException, this);
49943 this.store.load({});
49951 initEvents : function(){
49952 //Roo.form.ComboBox.superclass.initEvents.call(this);
49956 onDestroy : function(){
49959 this.store.un('beforeload', this.onBeforeLoad, this);
49960 this.store.un('load', this.onLoad, this);
49961 this.store.un('loadexception', this.onLoadException, this);
49963 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49967 fireKey : function(e){
49968 if(e.isNavKeyPress() && !this.list.isVisible()){
49969 this.fireEvent("specialkey", this, e);
49974 onResize: function(w, h){
49982 * Allow or prevent the user from directly editing the field text. If false is passed,
49983 * the user will only be able to select from the items defined in the dropdown list. This method
49984 * is the runtime equivalent of setting the 'editable' config option at config time.
49985 * @param {Boolean} value True to allow the user to directly edit the field text
49987 setEditable : function(value){
49992 onBeforeLoad : function(){
49994 Roo.log("Select before load");
49997 this.innerList.update(this.loadingText ?
49998 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
49999 //this.restrictHeight();
50000 this.selectedIndex = -1;
50004 onLoad : function(){
50007 var dom = this.el.dom;
50008 dom.innerHTML = '';
50009 var od = dom.ownerDocument;
50011 if (this.emptyText) {
50012 var op = od.createElement('option');
50013 op.setAttribute('value', '');
50014 op.innerHTML = String.format('{0}', this.emptyText);
50015 dom.appendChild(op);
50017 if(this.store.getCount() > 0){
50019 var vf = this.valueField;
50020 var df = this.displayField;
50021 this.store.data.each(function(r) {
50022 // which colmsn to use... testing - cdoe / title..
50023 var op = od.createElement('option');
50024 op.setAttribute('value', r.data[vf]);
50025 op.innerHTML = String.format('{0}', r.data[df]);
50026 dom.appendChild(op);
50028 if (typeof(this.defaultValue != 'undefined')) {
50029 this.setValue(this.defaultValue);
50034 //this.onEmptyResults();
50039 onLoadException : function()
50041 dom.innerHTML = '';
50043 Roo.log("Select on load exception");
50047 Roo.log(this.store.reader.jsonData);
50048 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50049 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50055 onTypeAhead : function(){
50060 onSelect : function(record, index){
50061 Roo.log('on select?');
50063 if(this.fireEvent('beforeselect', this, record, index) !== false){
50064 this.setFromData(index > -1 ? record.data : false);
50066 this.fireEvent('select', this, record, index);
50071 * Returns the currently selected field value or empty string if no value is set.
50072 * @return {String} value The selected value
50074 getValue : function(){
50075 var dom = this.el.dom;
50076 this.value = dom.options[dom.selectedIndex].value;
50082 * Clears any text/value currently set in the field
50084 clearValue : function(){
50086 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50091 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50092 * will be displayed in the field. If the value does not match the data value of an existing item,
50093 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50094 * Otherwise the field will be blank (although the value will still be set).
50095 * @param {String} value The value to match
50097 setValue : function(v){
50098 var d = this.el.dom;
50099 for (var i =0; i < d.options.length;i++) {
50100 if (v == d.options[i].value) {
50101 d.selectedIndex = i;
50109 * @property {Object} the last set data for the element
50114 * Sets the value of the field based on a object which is related to the record format for the store.
50115 * @param {Object} value the value to set as. or false on reset?
50117 setFromData : function(o){
50118 Roo.log('setfrom data?');
50124 reset : function(){
50128 findRecord : function(prop, value){
50133 if(this.store.getCount() > 0){
50134 this.store.each(function(r){
50135 if(r.data[prop] == value){
50145 getName: function()
50147 // returns hidden if it's set..
50148 if (!this.rendered) {return ''};
50149 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50157 onEmptyResults : function(){
50158 Roo.log('empty results');
50163 * Returns true if the dropdown list is expanded, else false.
50165 isExpanded : function(){
50170 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50171 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50172 * @param {String} value The data value of the item to select
50173 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50174 * selected item if it is not currently in view (defaults to true)
50175 * @return {Boolean} True if the value matched an item in the list, else false
50177 selectByValue : function(v, scrollIntoView){
50178 Roo.log('select By Value');
50181 if(v !== undefined && v !== null){
50182 var r = this.findRecord(this.valueField || this.displayField, v);
50184 this.select(this.store.indexOf(r), scrollIntoView);
50192 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50193 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50194 * @param {Number} index The zero-based index of the list item to select
50195 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50196 * selected item if it is not currently in view (defaults to true)
50198 select : function(index, scrollIntoView){
50199 Roo.log('select ');
50202 this.selectedIndex = index;
50203 this.view.select(index);
50204 if(scrollIntoView !== false){
50205 var el = this.view.getNode(index);
50207 this.innerList.scrollChildIntoView(el, false);
50215 validateBlur : function(){
50222 initQuery : function(){
50223 this.doQuery(this.getRawValue());
50227 doForce : function(){
50228 if(this.el.dom.value.length > 0){
50229 this.el.dom.value =
50230 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50236 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50237 * query allowing the query action to be canceled if needed.
50238 * @param {String} query The SQL query to execute
50239 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50240 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50241 * saved in the current store (defaults to false)
50243 doQuery : function(q, forceAll){
50245 Roo.log('doQuery?');
50246 if(q === undefined || q === null){
50251 forceAll: forceAll,
50255 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50259 forceAll = qe.forceAll;
50260 if(forceAll === true || (q.length >= this.minChars)){
50261 if(this.lastQuery != q || this.alwaysQuery){
50262 this.lastQuery = q;
50263 if(this.mode == 'local'){
50264 this.selectedIndex = -1;
50266 this.store.clearFilter();
50268 this.store.filter(this.displayField, q);
50272 this.store.baseParams[this.queryParam] = q;
50274 params: this.getParams(q)
50279 this.selectedIndex = -1;
50286 getParams : function(q){
50288 //p[this.queryParam] = q;
50291 p.limit = this.pageSize;
50297 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50299 collapse : function(){
50304 collapseIf : function(e){
50309 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50311 expand : function(){
50319 * @cfg {Boolean} grow
50323 * @cfg {Number} growMin
50327 * @cfg {Number} growMax
50335 setWidth : function()
50339 getResizeEl : function(){
50342 });//<script type="text/javasscript">
50346 * @class Roo.DDView
50347 * A DnD enabled version of Roo.View.
50348 * @param {Element/String} container The Element in which to create the View.
50349 * @param {String} tpl The template string used to create the markup for each element of the View
50350 * @param {Object} config The configuration properties. These include all the config options of
50351 * {@link Roo.View} plus some specific to this class.<br>
50353 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50354 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50356 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50357 .x-view-drag-insert-above {
50358 border-top:1px dotted #3366cc;
50360 .x-view-drag-insert-below {
50361 border-bottom:1px dotted #3366cc;
50367 Roo.DDView = function(container, tpl, config) {
50368 Roo.DDView.superclass.constructor.apply(this, arguments);
50369 this.getEl().setStyle("outline", "0px none");
50370 this.getEl().unselectable();
50371 if (this.dragGroup) {
50372 this.setDraggable(this.dragGroup.split(","));
50374 if (this.dropGroup) {
50375 this.setDroppable(this.dropGroup.split(","));
50377 if (this.deletable) {
50378 this.setDeletable();
50380 this.isDirtyFlag = false;
50386 Roo.extend(Roo.DDView, Roo.View, {
50387 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50388 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50389 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50390 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50394 reset: Roo.emptyFn,
50396 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50398 validate: function() {
50402 destroy: function() {
50403 this.purgeListeners();
50404 this.getEl.removeAllListeners();
50405 this.getEl().remove();
50406 if (this.dragZone) {
50407 if (this.dragZone.destroy) {
50408 this.dragZone.destroy();
50411 if (this.dropZone) {
50412 if (this.dropZone.destroy) {
50413 this.dropZone.destroy();
50418 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50419 getName: function() {
50423 /** Loads the View from a JSON string representing the Records to put into the Store. */
50424 setValue: function(v) {
50426 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50429 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50430 this.store.proxy = new Roo.data.MemoryProxy(data);
50434 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50435 getValue: function() {
50437 this.store.each(function(rec) {
50438 result += rec.id + ',';
50440 return result.substr(0, result.length - 1) + ')';
50443 getIds: function() {
50444 var i = 0, result = new Array(this.store.getCount());
50445 this.store.each(function(rec) {
50446 result[i++] = rec.id;
50451 isDirty: function() {
50452 return this.isDirtyFlag;
50456 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50457 * whole Element becomes the target, and this causes the drop gesture to append.
50459 getTargetFromEvent : function(e) {
50460 var target = e.getTarget();
50461 while ((target !== null) && (target.parentNode != this.el.dom)) {
50462 target = target.parentNode;
50465 target = this.el.dom.lastChild || this.el.dom;
50471 * Create the drag data which consists of an object which has the property "ddel" as
50472 * the drag proxy element.
50474 getDragData : function(e) {
50475 var target = this.findItemFromChild(e.getTarget());
50477 this.handleSelection(e);
50478 var selNodes = this.getSelectedNodes();
50481 copy: this.copy || (this.allowCopy && e.ctrlKey),
50485 var selectedIndices = this.getSelectedIndexes();
50486 for (var i = 0; i < selectedIndices.length; i++) {
50487 dragData.records.push(this.store.getAt(selectedIndices[i]));
50489 if (selNodes.length == 1) {
50490 dragData.ddel = target.cloneNode(true); // the div element
50492 var div = document.createElement('div'); // create the multi element drag "ghost"
50493 div.className = 'multi-proxy';
50494 for (var i = 0, len = selNodes.length; i < len; i++) {
50495 div.appendChild(selNodes[i].cloneNode(true));
50497 dragData.ddel = div;
50499 //console.log(dragData)
50500 //console.log(dragData.ddel.innerHTML)
50503 //console.log('nodragData')
50507 /** Specify to which ddGroup items in this DDView may be dragged. */
50508 setDraggable: function(ddGroup) {
50509 if (ddGroup instanceof Array) {
50510 Roo.each(ddGroup, this.setDraggable, this);
50513 if (this.dragZone) {
50514 this.dragZone.addToGroup(ddGroup);
50516 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50517 containerScroll: true,
50521 // Draggability implies selection. DragZone's mousedown selects the element.
50522 if (!this.multiSelect) { this.singleSelect = true; }
50524 // Wire the DragZone's handlers up to methods in *this*
50525 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50529 /** Specify from which ddGroup this DDView accepts drops. */
50530 setDroppable: function(ddGroup) {
50531 if (ddGroup instanceof Array) {
50532 Roo.each(ddGroup, this.setDroppable, this);
50535 if (this.dropZone) {
50536 this.dropZone.addToGroup(ddGroup);
50538 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50539 containerScroll: true,
50543 // Wire the DropZone's handlers up to methods in *this*
50544 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50545 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50546 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50547 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50548 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50552 /** Decide whether to drop above or below a View node. */
50553 getDropPoint : function(e, n, dd){
50554 if (n == this.el.dom) { return "above"; }
50555 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50556 var c = t + (b - t) / 2;
50557 var y = Roo.lib.Event.getPageY(e);
50565 onNodeEnter : function(n, dd, e, data){
50569 onNodeOver : function(n, dd, e, data){
50570 var pt = this.getDropPoint(e, n, dd);
50571 // set the insert point style on the target node
50572 var dragElClass = this.dropNotAllowed;
50575 if (pt == "above"){
50576 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50577 targetElClass = "x-view-drag-insert-above";
50579 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50580 targetElClass = "x-view-drag-insert-below";
50582 if (this.lastInsertClass != targetElClass){
50583 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50584 this.lastInsertClass = targetElClass;
50587 return dragElClass;
50590 onNodeOut : function(n, dd, e, data){
50591 this.removeDropIndicators(n);
50594 onNodeDrop : function(n, dd, e, data){
50595 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50598 var pt = this.getDropPoint(e, n, dd);
50599 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50600 if (pt == "below") { insertAt++; }
50601 for (var i = 0; i < data.records.length; i++) {
50602 var r = data.records[i];
50603 var dup = this.store.getById(r.id);
50604 if (dup && (dd != this.dragZone)) {
50605 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50608 this.store.insert(insertAt++, r.copy());
50610 data.source.isDirtyFlag = true;
50612 this.store.insert(insertAt++, r);
50614 this.isDirtyFlag = true;
50617 this.dragZone.cachedTarget = null;
50621 removeDropIndicators : function(n){
50623 Roo.fly(n).removeClass([
50624 "x-view-drag-insert-above",
50625 "x-view-drag-insert-below"]);
50626 this.lastInsertClass = "_noclass";
50631 * Utility method. Add a delete option to the DDView's context menu.
50632 * @param {String} imageUrl The URL of the "delete" icon image.
50634 setDeletable: function(imageUrl) {
50635 if (!this.singleSelect && !this.multiSelect) {
50636 this.singleSelect = true;
50638 var c = this.getContextMenu();
50639 this.contextMenu.on("itemclick", function(item) {
50642 this.remove(this.getSelectedIndexes());
50646 this.contextMenu.add({
50653 /** Return the context menu for this DDView. */
50654 getContextMenu: function() {
50655 if (!this.contextMenu) {
50656 // Create the View's context menu
50657 this.contextMenu = new Roo.menu.Menu({
50658 id: this.id + "-contextmenu"
50660 this.el.on("contextmenu", this.showContextMenu, this);
50662 return this.contextMenu;
50665 disableContextMenu: function() {
50666 if (this.contextMenu) {
50667 this.el.un("contextmenu", this.showContextMenu, this);
50671 showContextMenu: function(e, item) {
50672 item = this.findItemFromChild(e.getTarget());
50675 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50676 this.contextMenu.showAt(e.getXY());
50681 * Remove {@link Roo.data.Record}s at the specified indices.
50682 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50684 remove: function(selectedIndices) {
50685 selectedIndices = [].concat(selectedIndices);
50686 for (var i = 0; i < selectedIndices.length; i++) {
50687 var rec = this.store.getAt(selectedIndices[i]);
50688 this.store.remove(rec);
50693 * Double click fires the event, but also, if this is draggable, and there is only one other
50694 * related DropZone, it transfers the selected node.
50696 onDblClick : function(e){
50697 var item = this.findItemFromChild(e.getTarget());
50699 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50702 if (this.dragGroup) {
50703 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50704 while (targets.indexOf(this.dropZone) > -1) {
50705 targets.remove(this.dropZone);
50707 if (targets.length == 1) {
50708 this.dragZone.cachedTarget = null;
50709 var el = Roo.get(targets[0].getEl());
50710 var box = el.getBox(true);
50711 targets[0].onNodeDrop(el.dom, {
50713 xy: [box.x, box.y + box.height - 1]
50714 }, null, this.getDragData(e));
50720 handleSelection: function(e) {
50721 this.dragZone.cachedTarget = null;
50722 var item = this.findItemFromChild(e.getTarget());
50724 this.clearSelections(true);
50727 if (item && (this.multiSelect || this.singleSelect)){
50728 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50729 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50730 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50731 this.unselect(item);
50733 this.select(item, this.multiSelect && e.ctrlKey);
50734 this.lastSelection = item;
50739 onItemClick : function(item, index, e){
50740 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50746 unselect : function(nodeInfo, suppressEvent){
50747 var node = this.getNode(nodeInfo);
50748 if(node && this.isSelected(node)){
50749 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50750 Roo.fly(node).removeClass(this.selectedClass);
50751 this.selections.remove(node);
50752 if(!suppressEvent){
50753 this.fireEvent("selectionchange", this, this.selections);
50761 * Ext JS Library 1.1.1
50762 * Copyright(c) 2006-2007, Ext JS, LLC.
50764 * Originally Released Under LGPL - original licence link has changed is not relivant.
50767 * <script type="text/javascript">
50771 * @class Roo.LayoutManager
50772 * @extends Roo.util.Observable
50773 * Base class for layout managers.
50775 Roo.LayoutManager = function(container, config){
50776 Roo.LayoutManager.superclass.constructor.call(this);
50777 this.el = Roo.get(container);
50778 // ie scrollbar fix
50779 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50780 document.body.scroll = "no";
50781 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50782 this.el.position('relative');
50784 this.id = this.el.id;
50785 this.el.addClass("x-layout-container");
50786 /** false to disable window resize monitoring @type Boolean */
50787 this.monitorWindowResize = true;
50792 * Fires when a layout is performed.
50793 * @param {Roo.LayoutManager} this
50797 * @event regionresized
50798 * Fires when the user resizes a region.
50799 * @param {Roo.LayoutRegion} region The resized region
50800 * @param {Number} newSize The new size (width for east/west, height for north/south)
50802 "regionresized" : true,
50804 * @event regioncollapsed
50805 * Fires when a region is collapsed.
50806 * @param {Roo.LayoutRegion} region The collapsed region
50808 "regioncollapsed" : true,
50810 * @event regionexpanded
50811 * Fires when a region is expanded.
50812 * @param {Roo.LayoutRegion} region The expanded region
50814 "regionexpanded" : true
50816 this.updating = false;
50817 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50820 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50822 * Returns true if this layout is currently being updated
50823 * @return {Boolean}
50825 isUpdating : function(){
50826 return this.updating;
50830 * Suspend the LayoutManager from doing auto-layouts while
50831 * making multiple add or remove calls
50833 beginUpdate : function(){
50834 this.updating = true;
50838 * Restore auto-layouts and optionally disable the manager from performing a layout
50839 * @param {Boolean} noLayout true to disable a layout update
50841 endUpdate : function(noLayout){
50842 this.updating = false;
50848 layout: function(){
50852 onRegionResized : function(region, newSize){
50853 this.fireEvent("regionresized", region, newSize);
50857 onRegionCollapsed : function(region){
50858 this.fireEvent("regioncollapsed", region);
50861 onRegionExpanded : function(region){
50862 this.fireEvent("regionexpanded", region);
50866 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50867 * performs box-model adjustments.
50868 * @return {Object} The size as an object {width: (the width), height: (the height)}
50870 getViewSize : function(){
50872 if(this.el.dom != document.body){
50873 size = this.el.getSize();
50875 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50877 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50878 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50883 * Returns the Element this layout is bound to.
50884 * @return {Roo.Element}
50886 getEl : function(){
50891 * Returns the specified region.
50892 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50893 * @return {Roo.LayoutRegion}
50895 getRegion : function(target){
50896 return this.regions[target.toLowerCase()];
50899 onWindowResize : function(){
50900 if(this.monitorWindowResize){
50906 * Ext JS Library 1.1.1
50907 * Copyright(c) 2006-2007, Ext JS, LLC.
50909 * Originally Released Under LGPL - original licence link has changed is not relivant.
50912 * <script type="text/javascript">
50915 * @class Roo.BorderLayout
50916 * @extends Roo.LayoutManager
50917 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50918 * please see: <br><br>
50919 * <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>
50920 * <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>
50923 var layout = new Roo.BorderLayout(document.body, {
50957 preferredTabWidth: 150
50962 var CP = Roo.ContentPanel;
50964 layout.beginUpdate();
50965 layout.add("north", new CP("north", "North"));
50966 layout.add("south", new CP("south", {title: "South", closable: true}));
50967 layout.add("west", new CP("west", {title: "West"}));
50968 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50969 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50970 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50971 layout.getRegion("center").showPanel("center1");
50972 layout.endUpdate();
50975 <b>The container the layout is rendered into can be either the body element or any other element.
50976 If it is not the body element, the container needs to either be an absolute positioned element,
50977 or you will need to add "position:relative" to the css of the container. You will also need to specify
50978 the container size if it is not the body element.</b>
50981 * Create a new BorderLayout
50982 * @param {String/HTMLElement/Element} container The container this layout is bound to
50983 * @param {Object} config Configuration options
50985 Roo.BorderLayout = function(container, config){
50986 config = config || {};
50987 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50988 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50989 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50990 var target = this.factory.validRegions[i];
50991 if(config[target]){
50992 this.addRegion(target, config[target]);
50997 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
50999 * Creates and adds a new region if it doesn't already exist.
51000 * @param {String} target The target region key (north, south, east, west or center).
51001 * @param {Object} config The regions config object
51002 * @return {BorderLayoutRegion} The new region
51004 addRegion : function(target, config){
51005 if(!this.regions[target]){
51006 var r = this.factory.create(target, this, config);
51007 this.bindRegion(target, r);
51009 return this.regions[target];
51013 bindRegion : function(name, r){
51014 this.regions[name] = r;
51015 r.on("visibilitychange", this.layout, this);
51016 r.on("paneladded", this.layout, this);
51017 r.on("panelremoved", this.layout, this);
51018 r.on("invalidated", this.layout, this);
51019 r.on("resized", this.onRegionResized, this);
51020 r.on("collapsed", this.onRegionCollapsed, this);
51021 r.on("expanded", this.onRegionExpanded, this);
51025 * Performs a layout update.
51027 layout : function(){
51028 if(this.updating) {
51031 var size = this.getViewSize();
51032 var w = size.width;
51033 var h = size.height;
51038 //var x = 0, y = 0;
51040 var rs = this.regions;
51041 var north = rs["north"];
51042 var south = rs["south"];
51043 var west = rs["west"];
51044 var east = rs["east"];
51045 var center = rs["center"];
51046 //if(this.hideOnLayout){ // not supported anymore
51047 //c.el.setStyle("display", "none");
51049 if(north && north.isVisible()){
51050 var b = north.getBox();
51051 var m = north.getMargins();
51052 b.width = w - (m.left+m.right);
51055 centerY = b.height + b.y + m.bottom;
51056 centerH -= centerY;
51057 north.updateBox(this.safeBox(b));
51059 if(south && south.isVisible()){
51060 var b = south.getBox();
51061 var m = south.getMargins();
51062 b.width = w - (m.left+m.right);
51064 var totalHeight = (b.height + m.top + m.bottom);
51065 b.y = h - totalHeight + m.top;
51066 centerH -= totalHeight;
51067 south.updateBox(this.safeBox(b));
51069 if(west && west.isVisible()){
51070 var b = west.getBox();
51071 var m = west.getMargins();
51072 b.height = centerH - (m.top+m.bottom);
51074 b.y = centerY + m.top;
51075 var totalWidth = (b.width + m.left + m.right);
51076 centerX += totalWidth;
51077 centerW -= totalWidth;
51078 west.updateBox(this.safeBox(b));
51080 if(east && east.isVisible()){
51081 var b = east.getBox();
51082 var m = east.getMargins();
51083 b.height = centerH - (m.top+m.bottom);
51084 var totalWidth = (b.width + m.left + m.right);
51085 b.x = w - totalWidth + m.left;
51086 b.y = centerY + m.top;
51087 centerW -= totalWidth;
51088 east.updateBox(this.safeBox(b));
51091 var m = center.getMargins();
51093 x: centerX + m.left,
51094 y: centerY + m.top,
51095 width: centerW - (m.left+m.right),
51096 height: centerH - (m.top+m.bottom)
51098 //if(this.hideOnLayout){
51099 //center.el.setStyle("display", "block");
51101 center.updateBox(this.safeBox(centerBox));
51104 this.fireEvent("layout", this);
51108 safeBox : function(box){
51109 box.width = Math.max(0, box.width);
51110 box.height = Math.max(0, box.height);
51115 * Adds a ContentPanel (or subclass) to this layout.
51116 * @param {String} target The target region key (north, south, east, west or center).
51117 * @param {Roo.ContentPanel} panel The panel to add
51118 * @return {Roo.ContentPanel} The added panel
51120 add : function(target, panel){
51122 target = target.toLowerCase();
51123 return this.regions[target].add(panel);
51127 * Remove a ContentPanel (or subclass) to this layout.
51128 * @param {String} target The target region key (north, south, east, west or center).
51129 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51130 * @return {Roo.ContentPanel} The removed panel
51132 remove : function(target, panel){
51133 target = target.toLowerCase();
51134 return this.regions[target].remove(panel);
51138 * Searches all regions for a panel with the specified id
51139 * @param {String} panelId
51140 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51142 findPanel : function(panelId){
51143 var rs = this.regions;
51144 for(var target in rs){
51145 if(typeof rs[target] != "function"){
51146 var p = rs[target].getPanel(panelId);
51156 * Searches all regions for a panel with the specified id and activates (shows) it.
51157 * @param {String/ContentPanel} panelId The panels id or the panel itself
51158 * @return {Roo.ContentPanel} The shown panel or null
51160 showPanel : function(panelId) {
51161 var rs = this.regions;
51162 for(var target in rs){
51163 var r = rs[target];
51164 if(typeof r != "function"){
51165 if(r.hasPanel(panelId)){
51166 return r.showPanel(panelId);
51174 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51175 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51177 restoreState : function(provider){
51179 provider = Roo.state.Manager;
51181 var sm = new Roo.LayoutStateManager();
51182 sm.init(this, provider);
51186 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51187 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51188 * a valid ContentPanel config object. Example:
51190 // Create the main layout
51191 var layout = new Roo.BorderLayout('main-ct', {
51202 // Create and add multiple ContentPanels at once via configs
51205 id: 'source-files',
51207 title:'Ext Source Files',
51220 * @param {Object} regions An object containing ContentPanel configs by region name
51222 batchAdd : function(regions){
51223 this.beginUpdate();
51224 for(var rname in regions){
51225 var lr = this.regions[rname];
51227 this.addTypedPanels(lr, regions[rname]);
51234 addTypedPanels : function(lr, ps){
51235 if(typeof ps == 'string'){
51236 lr.add(new Roo.ContentPanel(ps));
51238 else if(ps instanceof Array){
51239 for(var i =0, len = ps.length; i < len; i++){
51240 this.addTypedPanels(lr, ps[i]);
51243 else if(!ps.events){ // raw config?
51245 delete ps.el; // prevent conflict
51246 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51248 else { // panel object assumed!
51253 * Adds a xtype elements to the layout.
51257 xtype : 'ContentPanel',
51264 xtype : 'NestedLayoutPanel',
51270 items : [ ... list of content panels or nested layout panels.. ]
51274 * @param {Object} cfg Xtype definition of item to add.
51276 addxtype : function(cfg)
51278 // basically accepts a pannel...
51279 // can accept a layout region..!?!?
51280 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51282 if (!cfg.xtype.match(/Panel$/)) {
51287 if (typeof(cfg.region) == 'undefined') {
51288 Roo.log("Failed to add Panel, region was not set");
51292 var region = cfg.region;
51298 xitems = cfg.items;
51305 case 'ContentPanel': // ContentPanel (el, cfg)
51306 case 'ScrollPanel': // ContentPanel (el, cfg)
51308 if(cfg.autoCreate) {
51309 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51311 var el = this.el.createChild();
51312 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51315 this.add(region, ret);
51319 case 'TreePanel': // our new panel!
51320 cfg.el = this.el.createChild();
51321 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51322 this.add(region, ret);
51325 case 'NestedLayoutPanel':
51326 // create a new Layout (which is a Border Layout...
51327 var el = this.el.createChild();
51328 var clayout = cfg.layout;
51330 clayout.items = clayout.items || [];
51331 // replace this exitems with the clayout ones..
51332 xitems = clayout.items;
51335 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51336 cfg.background = false;
51338 var layout = new Roo.BorderLayout(el, clayout);
51340 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51341 //console.log('adding nested layout panel ' + cfg.toSource());
51342 this.add(region, ret);
51343 nb = {}; /// find first...
51348 // needs grid and region
51350 //var el = this.getRegion(region).el.createChild();
51351 var el = this.el.createChild();
51352 // create the grid first...
51354 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51356 if (region == 'center' && this.active ) {
51357 cfg.background = false;
51359 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51361 this.add(region, ret);
51362 if (cfg.background) {
51363 ret.on('activate', function(gp) {
51364 if (!gp.grid.rendered) {
51379 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51381 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51382 this.add(region, ret);
51385 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51389 // GridPanel (grid, cfg)
51392 this.beginUpdate();
51396 Roo.each(xitems, function(i) {
51397 region = nb && i.region ? i.region : false;
51399 var add = ret.addxtype(i);
51402 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51403 if (!i.background) {
51404 abn[region] = nb[region] ;
51411 // make the last non-background panel active..
51412 //if (nb) { Roo.log(abn); }
51415 for(var r in abn) {
51416 region = this.getRegion(r);
51418 // tried using nb[r], but it does not work..
51420 region.showPanel(abn[r]);
51431 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51432 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51433 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51434 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51437 var CP = Roo.ContentPanel;
51439 var layout = Roo.BorderLayout.create({
51443 panels: [new CP("north", "North")]
51452 panels: [new CP("west", {title: "West"})]
51461 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51470 panels: [new CP("south", {title: "South", closable: true})]
51477 preferredTabWidth: 150,
51479 new CP("center1", {title: "Close Me", closable: true}),
51480 new CP("center2", {title: "Center Panel", closable: false})
51485 layout.getRegion("center").showPanel("center1");
51490 Roo.BorderLayout.create = function(config, targetEl){
51491 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51492 layout.beginUpdate();
51493 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51494 for(var j = 0, jlen = regions.length; j < jlen; j++){
51495 var lr = regions[j];
51496 if(layout.regions[lr] && config[lr].panels){
51497 var r = layout.regions[lr];
51498 var ps = config[lr].panels;
51499 layout.addTypedPanels(r, ps);
51502 layout.endUpdate();
51507 Roo.BorderLayout.RegionFactory = {
51509 validRegions : ["north","south","east","west","center"],
51512 create : function(target, mgr, config){
51513 target = target.toLowerCase();
51514 if(config.lightweight || config.basic){
51515 return new Roo.BasicLayoutRegion(mgr, config, target);
51519 return new Roo.NorthLayoutRegion(mgr, config);
51521 return new Roo.SouthLayoutRegion(mgr, config);
51523 return new Roo.EastLayoutRegion(mgr, config);
51525 return new Roo.WestLayoutRegion(mgr, config);
51527 return new Roo.CenterLayoutRegion(mgr, config);
51529 throw 'Layout region "'+target+'" not supported.';
51533 * Ext JS Library 1.1.1
51534 * Copyright(c) 2006-2007, Ext JS, LLC.
51536 * Originally Released Under LGPL - original licence link has changed is not relivant.
51539 * <script type="text/javascript">
51543 * @class Roo.BasicLayoutRegion
51544 * @extends Roo.util.Observable
51545 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51546 * and does not have a titlebar, tabs or any other features. All it does is size and position
51547 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51549 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51551 this.position = pos;
51554 * @scope Roo.BasicLayoutRegion
51558 * @event beforeremove
51559 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51560 * @param {Roo.LayoutRegion} this
51561 * @param {Roo.ContentPanel} panel The panel
51562 * @param {Object} e The cancel event object
51564 "beforeremove" : true,
51566 * @event invalidated
51567 * Fires when the layout for this region is changed.
51568 * @param {Roo.LayoutRegion} this
51570 "invalidated" : true,
51572 * @event visibilitychange
51573 * Fires when this region is shown or hidden
51574 * @param {Roo.LayoutRegion} this
51575 * @param {Boolean} visibility true or false
51577 "visibilitychange" : true,
51579 * @event paneladded
51580 * Fires when a panel is added.
51581 * @param {Roo.LayoutRegion} this
51582 * @param {Roo.ContentPanel} panel The panel
51584 "paneladded" : true,
51586 * @event panelremoved
51587 * Fires when a panel is removed.
51588 * @param {Roo.LayoutRegion} this
51589 * @param {Roo.ContentPanel} panel The panel
51591 "panelremoved" : true,
51593 * @event beforecollapse
51594 * Fires when this region before collapse.
51595 * @param {Roo.LayoutRegion} this
51597 "beforecollapse" : true,
51600 * Fires when this region is collapsed.
51601 * @param {Roo.LayoutRegion} this
51603 "collapsed" : true,
51606 * Fires when this region is expanded.
51607 * @param {Roo.LayoutRegion} this
51612 * Fires when this region is slid into view.
51613 * @param {Roo.LayoutRegion} this
51615 "slideshow" : true,
51618 * Fires when this region slides out of view.
51619 * @param {Roo.LayoutRegion} this
51621 "slidehide" : true,
51623 * @event panelactivated
51624 * Fires when a panel is activated.
51625 * @param {Roo.LayoutRegion} this
51626 * @param {Roo.ContentPanel} panel The activated panel
51628 "panelactivated" : true,
51631 * Fires when the user resizes this region.
51632 * @param {Roo.LayoutRegion} this
51633 * @param {Number} newSize The new size (width for east/west, height for north/south)
51637 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51638 this.panels = new Roo.util.MixedCollection();
51639 this.panels.getKey = this.getPanelId.createDelegate(this);
51641 this.activePanel = null;
51642 // ensure listeners are added...
51644 if (config.listeners || config.events) {
51645 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51646 listeners : config.listeners || {},
51647 events : config.events || {}
51651 if(skipConfig !== true){
51652 this.applyConfig(config);
51656 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51657 getPanelId : function(p){
51661 applyConfig : function(config){
51662 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51663 this.config = config;
51668 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51669 * the width, for horizontal (north, south) the height.
51670 * @param {Number} newSize The new width or height
51672 resizeTo : function(newSize){
51673 var el = this.el ? this.el :
51674 (this.activePanel ? this.activePanel.getEl() : null);
51676 switch(this.position){
51679 el.setWidth(newSize);
51680 this.fireEvent("resized", this, newSize);
51684 el.setHeight(newSize);
51685 this.fireEvent("resized", this, newSize);
51691 getBox : function(){
51692 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51695 getMargins : function(){
51696 return this.margins;
51699 updateBox : function(box){
51701 var el = this.activePanel.getEl();
51702 el.dom.style.left = box.x + "px";
51703 el.dom.style.top = box.y + "px";
51704 this.activePanel.setSize(box.width, box.height);
51708 * Returns the container element for this region.
51709 * @return {Roo.Element}
51711 getEl : function(){
51712 return this.activePanel;
51716 * Returns true if this region is currently visible.
51717 * @return {Boolean}
51719 isVisible : function(){
51720 return this.activePanel ? true : false;
51723 setActivePanel : function(panel){
51724 panel = this.getPanel(panel);
51725 if(this.activePanel && this.activePanel != panel){
51726 this.activePanel.setActiveState(false);
51727 this.activePanel.getEl().setLeftTop(-10000,-10000);
51729 this.activePanel = panel;
51730 panel.setActiveState(true);
51732 panel.setSize(this.box.width, this.box.height);
51734 this.fireEvent("panelactivated", this, panel);
51735 this.fireEvent("invalidated");
51739 * Show the specified panel.
51740 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51741 * @return {Roo.ContentPanel} The shown panel or null
51743 showPanel : function(panel){
51744 if(panel = this.getPanel(panel)){
51745 this.setActivePanel(panel);
51751 * Get the active panel for this region.
51752 * @return {Roo.ContentPanel} The active panel or null
51754 getActivePanel : function(){
51755 return this.activePanel;
51759 * Add the passed ContentPanel(s)
51760 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51761 * @return {Roo.ContentPanel} The panel added (if only one was added)
51763 add : function(panel){
51764 if(arguments.length > 1){
51765 for(var i = 0, len = arguments.length; i < len; i++) {
51766 this.add(arguments[i]);
51770 if(this.hasPanel(panel)){
51771 this.showPanel(panel);
51774 var el = panel.getEl();
51775 if(el.dom.parentNode != this.mgr.el.dom){
51776 this.mgr.el.dom.appendChild(el.dom);
51778 if(panel.setRegion){
51779 panel.setRegion(this);
51781 this.panels.add(panel);
51782 el.setStyle("position", "absolute");
51783 if(!panel.background){
51784 this.setActivePanel(panel);
51785 if(this.config.initialSize && this.panels.getCount()==1){
51786 this.resizeTo(this.config.initialSize);
51789 this.fireEvent("paneladded", this, panel);
51794 * Returns true if the panel is in this region.
51795 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51796 * @return {Boolean}
51798 hasPanel : function(panel){
51799 if(typeof panel == "object"){ // must be panel obj
51800 panel = panel.getId();
51802 return this.getPanel(panel) ? true : false;
51806 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51807 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51808 * @param {Boolean} preservePanel Overrides the config preservePanel option
51809 * @return {Roo.ContentPanel} The panel that was removed
51811 remove : function(panel, preservePanel){
51812 panel = this.getPanel(panel);
51817 this.fireEvent("beforeremove", this, panel, e);
51818 if(e.cancel === true){
51821 var panelId = panel.getId();
51822 this.panels.removeKey(panelId);
51827 * Returns the panel specified or null if it's not in this region.
51828 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51829 * @return {Roo.ContentPanel}
51831 getPanel : function(id){
51832 if(typeof id == "object"){ // must be panel obj
51835 return this.panels.get(id);
51839 * Returns this regions position (north/south/east/west/center).
51842 getPosition: function(){
51843 return this.position;
51847 * Ext JS Library 1.1.1
51848 * Copyright(c) 2006-2007, Ext JS, LLC.
51850 * Originally Released Under LGPL - original licence link has changed is not relivant.
51853 * <script type="text/javascript">
51857 * @class Roo.LayoutRegion
51858 * @extends Roo.BasicLayoutRegion
51859 * This class represents a region in a layout manager.
51860 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51861 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51862 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51863 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51864 * @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})
51865 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51866 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51867 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51868 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51869 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51870 * @cfg {String} title The title for the region (overrides panel titles)
51871 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51872 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51873 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51874 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51875 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51876 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51877 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51878 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51879 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51880 * @cfg {Boolean} showPin True to show a pin button
51881 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51882 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51883 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51884 * @cfg {Number} width For East/West panels
51885 * @cfg {Number} height For North/South panels
51886 * @cfg {Boolean} split To show the splitter
51887 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51889 Roo.LayoutRegion = function(mgr, config, pos){
51890 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51891 var dh = Roo.DomHelper;
51892 /** This region's container element
51893 * @type Roo.Element */
51894 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51895 /** This region's title element
51896 * @type Roo.Element */
51898 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51899 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51900 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51902 this.titleEl.enableDisplayMode();
51903 /** This region's title text element
51904 * @type HTMLElement */
51905 this.titleTextEl = this.titleEl.dom.firstChild;
51906 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51907 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51908 this.closeBtn.enableDisplayMode();
51909 this.closeBtn.on("click", this.closeClicked, this);
51910 this.closeBtn.hide();
51912 this.createBody(config);
51913 this.visible = true;
51914 this.collapsed = false;
51916 if(config.hideWhenEmpty){
51918 this.on("paneladded", this.validateVisibility, this);
51919 this.on("panelremoved", this.validateVisibility, this);
51921 this.applyConfig(config);
51924 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51926 createBody : function(){
51927 /** This region's body element
51928 * @type Roo.Element */
51929 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51932 applyConfig : function(c){
51933 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51934 var dh = Roo.DomHelper;
51935 if(c.titlebar !== false){
51936 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51937 this.collapseBtn.on("click", this.collapse, this);
51938 this.collapseBtn.enableDisplayMode();
51940 if(c.showPin === true || this.showPin){
51941 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51942 this.stickBtn.enableDisplayMode();
51943 this.stickBtn.on("click", this.expand, this);
51944 this.stickBtn.hide();
51947 /** This region's collapsed element
51948 * @type Roo.Element */
51949 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51950 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51952 if(c.floatable !== false){
51953 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51954 this.collapsedEl.on("click", this.collapseClick, this);
51957 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51958 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51959 id: "message", unselectable: "on", style:{"float":"left"}});
51960 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51962 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51963 this.expandBtn.on("click", this.expand, this);
51965 if(this.collapseBtn){
51966 this.collapseBtn.setVisible(c.collapsible == true);
51968 this.cmargins = c.cmargins || this.cmargins ||
51969 (this.position == "west" || this.position == "east" ?
51970 {top: 0, left: 2, right:2, bottom: 0} :
51971 {top: 2, left: 0, right:0, bottom: 2});
51972 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51973 this.bottomTabs = c.tabPosition != "top";
51974 this.autoScroll = c.autoScroll || false;
51975 if(this.autoScroll){
51976 this.bodyEl.setStyle("overflow", "auto");
51978 this.bodyEl.setStyle("overflow", "hidden");
51980 //if(c.titlebar !== false){
51981 if((!c.titlebar && !c.title) || c.titlebar === false){
51982 this.titleEl.hide();
51984 this.titleEl.show();
51986 this.titleTextEl.innerHTML = c.title;
51990 this.duration = c.duration || .30;
51991 this.slideDuration = c.slideDuration || .45;
51994 this.collapse(true);
52001 * Returns true if this region is currently visible.
52002 * @return {Boolean}
52004 isVisible : function(){
52005 return this.visible;
52009 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52010 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52012 setCollapsedTitle : function(title){
52013 title = title || " ";
52014 if(this.collapsedTitleTextEl){
52015 this.collapsedTitleTextEl.innerHTML = title;
52019 getBox : function(){
52021 if(!this.collapsed){
52022 b = this.el.getBox(false, true);
52024 b = this.collapsedEl.getBox(false, true);
52029 getMargins : function(){
52030 return this.collapsed ? this.cmargins : this.margins;
52033 highlight : function(){
52034 this.el.addClass("x-layout-panel-dragover");
52037 unhighlight : function(){
52038 this.el.removeClass("x-layout-panel-dragover");
52041 updateBox : function(box){
52043 if(!this.collapsed){
52044 this.el.dom.style.left = box.x + "px";
52045 this.el.dom.style.top = box.y + "px";
52046 this.updateBody(box.width, box.height);
52048 this.collapsedEl.dom.style.left = box.x + "px";
52049 this.collapsedEl.dom.style.top = box.y + "px";
52050 this.collapsedEl.setSize(box.width, box.height);
52053 this.tabs.autoSizeTabs();
52057 updateBody : function(w, h){
52059 this.el.setWidth(w);
52060 w -= this.el.getBorderWidth("rl");
52061 if(this.config.adjustments){
52062 w += this.config.adjustments[0];
52066 this.el.setHeight(h);
52067 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52068 h -= this.el.getBorderWidth("tb");
52069 if(this.config.adjustments){
52070 h += this.config.adjustments[1];
52072 this.bodyEl.setHeight(h);
52074 h = this.tabs.syncHeight(h);
52077 if(this.panelSize){
52078 w = w !== null ? w : this.panelSize.width;
52079 h = h !== null ? h : this.panelSize.height;
52081 if(this.activePanel){
52082 var el = this.activePanel.getEl();
52083 w = w !== null ? w : el.getWidth();
52084 h = h !== null ? h : el.getHeight();
52085 this.panelSize = {width: w, height: h};
52086 this.activePanel.setSize(w, h);
52088 if(Roo.isIE && this.tabs){
52089 this.tabs.el.repaint();
52094 * Returns the container element for this region.
52095 * @return {Roo.Element}
52097 getEl : function(){
52102 * Hides this region.
52105 if(!this.collapsed){
52106 this.el.dom.style.left = "-2000px";
52109 this.collapsedEl.dom.style.left = "-2000px";
52110 this.collapsedEl.hide();
52112 this.visible = false;
52113 this.fireEvent("visibilitychange", this, false);
52117 * Shows this region if it was previously hidden.
52120 if(!this.collapsed){
52123 this.collapsedEl.show();
52125 this.visible = true;
52126 this.fireEvent("visibilitychange", this, true);
52129 closeClicked : function(){
52130 if(this.activePanel){
52131 this.remove(this.activePanel);
52135 collapseClick : function(e){
52137 e.stopPropagation();
52140 e.stopPropagation();
52146 * Collapses this region.
52147 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52149 collapse : function(skipAnim, skipCheck = false){
52150 if(this.collapsed) {
52154 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52156 this.collapsed = true;
52158 this.split.el.hide();
52160 if(this.config.animate && skipAnim !== true){
52161 this.fireEvent("invalidated", this);
52162 this.animateCollapse();
52164 this.el.setLocation(-20000,-20000);
52166 this.collapsedEl.show();
52167 this.fireEvent("collapsed", this);
52168 this.fireEvent("invalidated", this);
52174 animateCollapse : function(){
52179 * Expands this region if it was previously collapsed.
52180 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52181 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52183 expand : function(e, skipAnim){
52185 e.stopPropagation();
52187 if(!this.collapsed || this.el.hasActiveFx()) {
52191 this.afterSlideIn();
52194 this.collapsed = false;
52195 if(this.config.animate && skipAnim !== true){
52196 this.animateExpand();
52200 this.split.el.show();
52202 this.collapsedEl.setLocation(-2000,-2000);
52203 this.collapsedEl.hide();
52204 this.fireEvent("invalidated", this);
52205 this.fireEvent("expanded", this);
52209 animateExpand : function(){
52213 initTabs : function()
52215 this.bodyEl.setStyle("overflow", "hidden");
52216 var ts = new Roo.TabPanel(
52219 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52220 disableTooltips: this.config.disableTabTips,
52221 toolbar : this.config.toolbar
52224 if(this.config.hideTabs){
52225 ts.stripWrap.setDisplayed(false);
52228 ts.resizeTabs = this.config.resizeTabs === true;
52229 ts.minTabWidth = this.config.minTabWidth || 40;
52230 ts.maxTabWidth = this.config.maxTabWidth || 250;
52231 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52232 ts.monitorResize = false;
52233 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52234 ts.bodyEl.addClass('x-layout-tabs-body');
52235 this.panels.each(this.initPanelAsTab, this);
52238 initPanelAsTab : function(panel){
52239 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52240 this.config.closeOnTab && panel.isClosable());
52241 if(panel.tabTip !== undefined){
52242 ti.setTooltip(panel.tabTip);
52244 ti.on("activate", function(){
52245 this.setActivePanel(panel);
52247 if(this.config.closeOnTab){
52248 ti.on("beforeclose", function(t, e){
52250 this.remove(panel);
52256 updatePanelTitle : function(panel, title){
52257 if(this.activePanel == panel){
52258 this.updateTitle(title);
52261 var ti = this.tabs.getTab(panel.getEl().id);
52263 if(panel.tabTip !== undefined){
52264 ti.setTooltip(panel.tabTip);
52269 updateTitle : function(title){
52270 if(this.titleTextEl && !this.config.title){
52271 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52275 setActivePanel : function(panel){
52276 panel = this.getPanel(panel);
52277 if(this.activePanel && this.activePanel != panel){
52278 this.activePanel.setActiveState(false);
52280 this.activePanel = panel;
52281 panel.setActiveState(true);
52282 if(this.panelSize){
52283 panel.setSize(this.panelSize.width, this.panelSize.height);
52286 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52288 this.updateTitle(panel.getTitle());
52290 this.fireEvent("invalidated", this);
52292 this.fireEvent("panelactivated", this, panel);
52296 * Shows the specified panel.
52297 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52298 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52300 showPanel : function(panel)
52302 panel = this.getPanel(panel);
52305 var tab = this.tabs.getTab(panel.getEl().id);
52306 if(tab.isHidden()){
52307 this.tabs.unhideTab(tab.id);
52311 this.setActivePanel(panel);
52318 * Get the active panel for this region.
52319 * @return {Roo.ContentPanel} The active panel or null
52321 getActivePanel : function(){
52322 return this.activePanel;
52325 validateVisibility : function(){
52326 if(this.panels.getCount() < 1){
52327 this.updateTitle(" ");
52328 this.closeBtn.hide();
52331 if(!this.isVisible()){
52338 * Adds the passed ContentPanel(s) to this region.
52339 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52340 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52342 add : function(panel){
52343 if(arguments.length > 1){
52344 for(var i = 0, len = arguments.length; i < len; i++) {
52345 this.add(arguments[i]);
52349 if(this.hasPanel(panel)){
52350 this.showPanel(panel);
52353 panel.setRegion(this);
52354 this.panels.add(panel);
52355 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52356 this.bodyEl.dom.appendChild(panel.getEl().dom);
52357 if(panel.background !== true){
52358 this.setActivePanel(panel);
52360 this.fireEvent("paneladded", this, panel);
52366 this.initPanelAsTab(panel);
52368 if(panel.background !== true){
52369 this.tabs.activate(panel.getEl().id);
52371 this.fireEvent("paneladded", this, panel);
52376 * Hides the tab for the specified panel.
52377 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52379 hidePanel : function(panel){
52380 if(this.tabs && (panel = this.getPanel(panel))){
52381 this.tabs.hideTab(panel.getEl().id);
52386 * Unhides the tab for a previously hidden panel.
52387 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52389 unhidePanel : function(panel){
52390 if(this.tabs && (panel = this.getPanel(panel))){
52391 this.tabs.unhideTab(panel.getEl().id);
52395 clearPanels : function(){
52396 while(this.panels.getCount() > 0){
52397 this.remove(this.panels.first());
52402 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52403 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52404 * @param {Boolean} preservePanel Overrides the config preservePanel option
52405 * @return {Roo.ContentPanel} The panel that was removed
52407 remove : function(panel, preservePanel){
52408 panel = this.getPanel(panel);
52413 this.fireEvent("beforeremove", this, panel, e);
52414 if(e.cancel === true){
52417 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52418 var panelId = panel.getId();
52419 this.panels.removeKey(panelId);
52421 document.body.appendChild(panel.getEl().dom);
52424 this.tabs.removeTab(panel.getEl().id);
52425 }else if (!preservePanel){
52426 this.bodyEl.dom.removeChild(panel.getEl().dom);
52428 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52429 var p = this.panels.first();
52430 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52431 tempEl.appendChild(p.getEl().dom);
52432 this.bodyEl.update("");
52433 this.bodyEl.dom.appendChild(p.getEl().dom);
52435 this.updateTitle(p.getTitle());
52437 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52438 this.setActivePanel(p);
52440 panel.setRegion(null);
52441 if(this.activePanel == panel){
52442 this.activePanel = null;
52444 if(this.config.autoDestroy !== false && preservePanel !== true){
52445 try{panel.destroy();}catch(e){}
52447 this.fireEvent("panelremoved", this, panel);
52452 * Returns the TabPanel component used by this region
52453 * @return {Roo.TabPanel}
52455 getTabs : function(){
52459 createTool : function(parentEl, className){
52460 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52461 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52462 btn.addClassOnOver("x-layout-tools-button-over");
52467 * Ext JS Library 1.1.1
52468 * Copyright(c) 2006-2007, Ext JS, LLC.
52470 * Originally Released Under LGPL - original licence link has changed is not relivant.
52473 * <script type="text/javascript">
52479 * @class Roo.SplitLayoutRegion
52480 * @extends Roo.LayoutRegion
52481 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52483 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52484 this.cursor = cursor;
52485 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52488 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52489 splitTip : "Drag to resize.",
52490 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52491 useSplitTips : false,
52493 applyConfig : function(config){
52494 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52497 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52498 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52499 /** The SplitBar for this region
52500 * @type Roo.SplitBar */
52501 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52502 this.split.on("moved", this.onSplitMove, this);
52503 this.split.useShim = config.useShim === true;
52504 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52505 if(this.useSplitTips){
52506 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52508 if(config.collapsible){
52509 this.split.el.on("dblclick", this.collapse, this);
52512 if(typeof config.minSize != "undefined"){
52513 this.split.minSize = config.minSize;
52515 if(typeof config.maxSize != "undefined"){
52516 this.split.maxSize = config.maxSize;
52518 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52519 this.hideSplitter();
52524 getHMaxSize : function(){
52525 var cmax = this.config.maxSize || 10000;
52526 var center = this.mgr.getRegion("center");
52527 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52530 getVMaxSize : function(){
52531 var cmax = this.config.maxSize || 10000;
52532 var center = this.mgr.getRegion("center");
52533 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52536 onSplitMove : function(split, newSize){
52537 this.fireEvent("resized", this, newSize);
52541 * Returns the {@link Roo.SplitBar} for this region.
52542 * @return {Roo.SplitBar}
52544 getSplitBar : function(){
52549 this.hideSplitter();
52550 Roo.SplitLayoutRegion.superclass.hide.call(this);
52553 hideSplitter : function(){
52555 this.split.el.setLocation(-2000,-2000);
52556 this.split.el.hide();
52562 this.split.el.show();
52564 Roo.SplitLayoutRegion.superclass.show.call(this);
52567 beforeSlide: function(){
52568 if(Roo.isGecko){// firefox overflow auto bug workaround
52569 this.bodyEl.clip();
52571 this.tabs.bodyEl.clip();
52573 if(this.activePanel){
52574 this.activePanel.getEl().clip();
52576 if(this.activePanel.beforeSlide){
52577 this.activePanel.beforeSlide();
52583 afterSlide : function(){
52584 if(Roo.isGecko){// firefox overflow auto bug workaround
52585 this.bodyEl.unclip();
52587 this.tabs.bodyEl.unclip();
52589 if(this.activePanel){
52590 this.activePanel.getEl().unclip();
52591 if(this.activePanel.afterSlide){
52592 this.activePanel.afterSlide();
52598 initAutoHide : function(){
52599 if(this.autoHide !== false){
52600 if(!this.autoHideHd){
52601 var st = new Roo.util.DelayedTask(this.slideIn, this);
52602 this.autoHideHd = {
52603 "mouseout": function(e){
52604 if(!e.within(this.el, true)){
52608 "mouseover" : function(e){
52614 this.el.on(this.autoHideHd);
52618 clearAutoHide : function(){
52619 if(this.autoHide !== false){
52620 this.el.un("mouseout", this.autoHideHd.mouseout);
52621 this.el.un("mouseover", this.autoHideHd.mouseover);
52625 clearMonitor : function(){
52626 Roo.get(document).un("click", this.slideInIf, this);
52629 // these names are backwards but not changed for compat
52630 slideOut : function(){
52631 if(this.isSlid || this.el.hasActiveFx()){
52634 this.isSlid = true;
52635 if(this.collapseBtn){
52636 this.collapseBtn.hide();
52638 this.closeBtnState = this.closeBtn.getStyle('display');
52639 this.closeBtn.hide();
52641 this.stickBtn.show();
52644 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52645 this.beforeSlide();
52646 this.el.setStyle("z-index", 10001);
52647 this.el.slideIn(this.getSlideAnchor(), {
52648 callback: function(){
52650 this.initAutoHide();
52651 Roo.get(document).on("click", this.slideInIf, this);
52652 this.fireEvent("slideshow", this);
52659 afterSlideIn : function(){
52660 this.clearAutoHide();
52661 this.isSlid = false;
52662 this.clearMonitor();
52663 this.el.setStyle("z-index", "");
52664 if(this.collapseBtn){
52665 this.collapseBtn.show();
52667 this.closeBtn.setStyle('display', this.closeBtnState);
52669 this.stickBtn.hide();
52671 this.fireEvent("slidehide", this);
52674 slideIn : function(cb){
52675 if(!this.isSlid || this.el.hasActiveFx()){
52679 this.isSlid = false;
52680 this.beforeSlide();
52681 this.el.slideOut(this.getSlideAnchor(), {
52682 callback: function(){
52683 this.el.setLeftTop(-10000, -10000);
52685 this.afterSlideIn();
52693 slideInIf : function(e){
52694 if(!e.within(this.el)){
52699 animateCollapse : function(){
52700 this.beforeSlide();
52701 this.el.setStyle("z-index", 20000);
52702 var anchor = this.getSlideAnchor();
52703 this.el.slideOut(anchor, {
52704 callback : function(){
52705 this.el.setStyle("z-index", "");
52706 this.collapsedEl.slideIn(anchor, {duration:.3});
52708 this.el.setLocation(-10000,-10000);
52710 this.fireEvent("collapsed", this);
52717 animateExpand : function(){
52718 this.beforeSlide();
52719 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52720 this.el.setStyle("z-index", 20000);
52721 this.collapsedEl.hide({
52724 this.el.slideIn(this.getSlideAnchor(), {
52725 callback : function(){
52726 this.el.setStyle("z-index", "");
52729 this.split.el.show();
52731 this.fireEvent("invalidated", this);
52732 this.fireEvent("expanded", this);
52760 getAnchor : function(){
52761 return this.anchors[this.position];
52764 getCollapseAnchor : function(){
52765 return this.canchors[this.position];
52768 getSlideAnchor : function(){
52769 return this.sanchors[this.position];
52772 getAlignAdj : function(){
52773 var cm = this.cmargins;
52774 switch(this.position){
52790 getExpandAdj : function(){
52791 var c = this.collapsedEl, cm = this.cmargins;
52792 switch(this.position){
52794 return [-(cm.right+c.getWidth()+cm.left), 0];
52797 return [cm.right+c.getWidth()+cm.left, 0];
52800 return [0, -(cm.top+cm.bottom+c.getHeight())];
52803 return [0, cm.top+cm.bottom+c.getHeight()];
52809 * Ext JS Library 1.1.1
52810 * Copyright(c) 2006-2007, Ext JS, LLC.
52812 * Originally Released Under LGPL - original licence link has changed is not relivant.
52815 * <script type="text/javascript">
52818 * These classes are private internal classes
52820 Roo.CenterLayoutRegion = function(mgr, config){
52821 Roo.LayoutRegion.call(this, mgr, config, "center");
52822 this.visible = true;
52823 this.minWidth = config.minWidth || 20;
52824 this.minHeight = config.minHeight || 20;
52827 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52829 // center panel can't be hidden
52833 // center panel can't be hidden
52836 getMinWidth: function(){
52837 return this.minWidth;
52840 getMinHeight: function(){
52841 return this.minHeight;
52846 Roo.NorthLayoutRegion = function(mgr, config){
52847 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52849 this.split.placement = Roo.SplitBar.TOP;
52850 this.split.orientation = Roo.SplitBar.VERTICAL;
52851 this.split.el.addClass("x-layout-split-v");
52853 var size = config.initialSize || config.height;
52854 if(typeof size != "undefined"){
52855 this.el.setHeight(size);
52858 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52859 orientation: Roo.SplitBar.VERTICAL,
52860 getBox : function(){
52861 if(this.collapsed){
52862 return this.collapsedEl.getBox();
52864 var box = this.el.getBox();
52866 box.height += this.split.el.getHeight();
52871 updateBox : function(box){
52872 if(this.split && !this.collapsed){
52873 box.height -= this.split.el.getHeight();
52874 this.split.el.setLeft(box.x);
52875 this.split.el.setTop(box.y+box.height);
52876 this.split.el.setWidth(box.width);
52878 if(this.collapsed){
52879 this.updateBody(box.width, null);
52881 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52885 Roo.SouthLayoutRegion = function(mgr, config){
52886 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52888 this.split.placement = Roo.SplitBar.BOTTOM;
52889 this.split.orientation = Roo.SplitBar.VERTICAL;
52890 this.split.el.addClass("x-layout-split-v");
52892 var size = config.initialSize || config.height;
52893 if(typeof size != "undefined"){
52894 this.el.setHeight(size);
52897 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52898 orientation: Roo.SplitBar.VERTICAL,
52899 getBox : function(){
52900 if(this.collapsed){
52901 return this.collapsedEl.getBox();
52903 var box = this.el.getBox();
52905 var sh = this.split.el.getHeight();
52912 updateBox : function(box){
52913 if(this.split && !this.collapsed){
52914 var sh = this.split.el.getHeight();
52917 this.split.el.setLeft(box.x);
52918 this.split.el.setTop(box.y-sh);
52919 this.split.el.setWidth(box.width);
52921 if(this.collapsed){
52922 this.updateBody(box.width, null);
52924 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52928 Roo.EastLayoutRegion = function(mgr, config){
52929 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52931 this.split.placement = Roo.SplitBar.RIGHT;
52932 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52933 this.split.el.addClass("x-layout-split-h");
52935 var size = config.initialSize || config.width;
52936 if(typeof size != "undefined"){
52937 this.el.setWidth(size);
52940 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52941 orientation: Roo.SplitBar.HORIZONTAL,
52942 getBox : function(){
52943 if(this.collapsed){
52944 return this.collapsedEl.getBox();
52946 var box = this.el.getBox();
52948 var sw = this.split.el.getWidth();
52955 updateBox : function(box){
52956 if(this.split && !this.collapsed){
52957 var sw = this.split.el.getWidth();
52959 this.split.el.setLeft(box.x);
52960 this.split.el.setTop(box.y);
52961 this.split.el.setHeight(box.height);
52964 if(this.collapsed){
52965 this.updateBody(null, box.height);
52967 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52971 Roo.WestLayoutRegion = function(mgr, config){
52972 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52974 this.split.placement = Roo.SplitBar.LEFT;
52975 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52976 this.split.el.addClass("x-layout-split-h");
52978 var size = config.initialSize || config.width;
52979 if(typeof size != "undefined"){
52980 this.el.setWidth(size);
52983 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52984 orientation: Roo.SplitBar.HORIZONTAL,
52985 getBox : function(){
52986 if(this.collapsed){
52987 return this.collapsedEl.getBox();
52989 var box = this.el.getBox();
52991 box.width += this.split.el.getWidth();
52996 updateBox : function(box){
52997 if(this.split && !this.collapsed){
52998 var sw = this.split.el.getWidth();
53000 this.split.el.setLeft(box.x+box.width);
53001 this.split.el.setTop(box.y);
53002 this.split.el.setHeight(box.height);
53004 if(this.collapsed){
53005 this.updateBody(null, box.height);
53007 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53012 * Ext JS Library 1.1.1
53013 * Copyright(c) 2006-2007, Ext JS, LLC.
53015 * Originally Released Under LGPL - original licence link has changed is not relivant.
53018 * <script type="text/javascript">
53023 * Private internal class for reading and applying state
53025 Roo.LayoutStateManager = function(layout){
53026 // default empty state
53035 Roo.LayoutStateManager.prototype = {
53036 init : function(layout, provider){
53037 this.provider = provider;
53038 var state = provider.get(layout.id+"-layout-state");
53040 var wasUpdating = layout.isUpdating();
53042 layout.beginUpdate();
53044 for(var key in state){
53045 if(typeof state[key] != "function"){
53046 var rstate = state[key];
53047 var r = layout.getRegion(key);
53050 r.resizeTo(rstate.size);
53052 if(rstate.collapsed == true){
53055 r.expand(null, true);
53061 layout.endUpdate();
53063 this.state = state;
53065 this.layout = layout;
53066 layout.on("regionresized", this.onRegionResized, this);
53067 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53068 layout.on("regionexpanded", this.onRegionExpanded, this);
53071 storeState : function(){
53072 this.provider.set(this.layout.id+"-layout-state", this.state);
53075 onRegionResized : function(region, newSize){
53076 this.state[region.getPosition()].size = newSize;
53080 onRegionCollapsed : function(region){
53081 this.state[region.getPosition()].collapsed = true;
53085 onRegionExpanded : function(region){
53086 this.state[region.getPosition()].collapsed = false;
53091 * Ext JS Library 1.1.1
53092 * Copyright(c) 2006-2007, Ext JS, LLC.
53094 * Originally Released Under LGPL - original licence link has changed is not relivant.
53097 * <script type="text/javascript">
53100 * @class Roo.ContentPanel
53101 * @extends Roo.util.Observable
53102 * A basic ContentPanel element.
53103 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53104 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53105 * @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
53106 * @cfg {Boolean} closable True if the panel can be closed/removed
53107 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53108 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53109 * @cfg {Toolbar} toolbar A toolbar for this panel
53110 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53111 * @cfg {String} title The title for this panel
53112 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53113 * @cfg {String} url Calls {@link #setUrl} with this value
53114 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53115 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53116 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53117 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53120 * Create a new ContentPanel.
53121 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53122 * @param {String/Object} config A string to set only the title or a config object
53123 * @param {String} content (optional) Set the HTML content for this panel
53124 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53126 Roo.ContentPanel = function(el, config, content){
53130 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53134 if (config && config.parentLayout) {
53135 el = config.parentLayout.el.createChild();
53138 if(el.autoCreate){ // xtype is available if this is called from factory
53142 this.el = Roo.get(el);
53143 if(!this.el && config && config.autoCreate){
53144 if(typeof config.autoCreate == "object"){
53145 if(!config.autoCreate.id){
53146 config.autoCreate.id = config.id||el;
53148 this.el = Roo.DomHelper.append(document.body,
53149 config.autoCreate, true);
53151 this.el = Roo.DomHelper.append(document.body,
53152 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53155 this.closable = false;
53156 this.loaded = false;
53157 this.active = false;
53158 if(typeof config == "string"){
53159 this.title = config;
53161 Roo.apply(this, config);
53164 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53165 this.wrapEl = this.el.wrap();
53166 this.toolbar.container = this.el.insertSibling(false, 'before');
53167 this.toolbar = new Roo.Toolbar(this.toolbar);
53170 // xtype created footer. - not sure if will work as we normally have to render first..
53171 if (this.footer && !this.footer.el && this.footer.xtype) {
53172 if (!this.wrapEl) {
53173 this.wrapEl = this.el.wrap();
53176 this.footer.container = this.wrapEl.createChild();
53178 this.footer = Roo.factory(this.footer, Roo);
53183 this.resizeEl = Roo.get(this.resizeEl, true);
53185 this.resizeEl = this.el;
53187 // handle view.xtype
53195 * Fires when this panel is activated.
53196 * @param {Roo.ContentPanel} this
53200 * @event deactivate
53201 * Fires when this panel is activated.
53202 * @param {Roo.ContentPanel} this
53204 "deactivate" : true,
53208 * Fires when this panel is resized if fitToFrame is true.
53209 * @param {Roo.ContentPanel} this
53210 * @param {Number} width The width after any component adjustments
53211 * @param {Number} height The height after any component adjustments
53217 * Fires when this tab is created
53218 * @param {Roo.ContentPanel} this
53229 if(this.autoScroll){
53230 this.resizeEl.setStyle("overflow", "auto");
53232 // fix randome scrolling
53233 this.el.on('scroll', function() {
53234 Roo.log('fix random scolling');
53235 this.scrollTo('top',0);
53238 content = content || this.content;
53240 this.setContent(content);
53242 if(config && config.url){
53243 this.setUrl(this.url, this.params, this.loadOnce);
53248 Roo.ContentPanel.superclass.constructor.call(this);
53250 if (this.view && typeof(this.view.xtype) != 'undefined') {
53251 this.view.el = this.el.appendChild(document.createElement("div"));
53252 this.view = Roo.factory(this.view);
53253 this.view.render && this.view.render(false, '');
53257 this.fireEvent('render', this);
53260 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53262 setRegion : function(region){
53263 this.region = region;
53265 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53267 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53272 * Returns the toolbar for this Panel if one was configured.
53273 * @return {Roo.Toolbar}
53275 getToolbar : function(){
53276 return this.toolbar;
53279 setActiveState : function(active){
53280 this.active = active;
53282 this.fireEvent("deactivate", this);
53284 this.fireEvent("activate", this);
53288 * Updates this panel's element
53289 * @param {String} content The new content
53290 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53292 setContent : function(content, loadScripts){
53293 this.el.update(content, loadScripts);
53296 ignoreResize : function(w, h){
53297 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53300 this.lastSize = {width: w, height: h};
53305 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53306 * @return {Roo.UpdateManager} The UpdateManager
53308 getUpdateManager : function(){
53309 return this.el.getUpdateManager();
53312 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53313 * @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:
53316 url: "your-url.php",
53317 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53318 callback: yourFunction,
53319 scope: yourObject, //(optional scope)
53322 text: "Loading...",
53327 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53328 * 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.
53329 * @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}
53330 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53331 * @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.
53332 * @return {Roo.ContentPanel} this
53335 var um = this.el.getUpdateManager();
53336 um.update.apply(um, arguments);
53342 * 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.
53343 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53344 * @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)
53345 * @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)
53346 * @return {Roo.UpdateManager} The UpdateManager
53348 setUrl : function(url, params, loadOnce){
53349 if(this.refreshDelegate){
53350 this.removeListener("activate", this.refreshDelegate);
53352 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53353 this.on("activate", this.refreshDelegate);
53354 return this.el.getUpdateManager();
53357 _handleRefresh : function(url, params, loadOnce){
53358 if(!loadOnce || !this.loaded){
53359 var updater = this.el.getUpdateManager();
53360 updater.update(url, params, this._setLoaded.createDelegate(this));
53364 _setLoaded : function(){
53365 this.loaded = true;
53369 * Returns this panel's id
53372 getId : function(){
53377 * Returns this panel's element - used by regiosn to add.
53378 * @return {Roo.Element}
53380 getEl : function(){
53381 return this.wrapEl || this.el;
53384 adjustForComponents : function(width, height)
53386 //Roo.log('adjustForComponents ');
53387 if(this.resizeEl != this.el){
53388 width -= this.el.getFrameWidth('lr');
53389 height -= this.el.getFrameWidth('tb');
53392 var te = this.toolbar.getEl();
53393 height -= te.getHeight();
53394 te.setWidth(width);
53397 var te = this.footer.getEl();
53398 Roo.log("footer:" + te.getHeight());
53400 height -= te.getHeight();
53401 te.setWidth(width);
53405 if(this.adjustments){
53406 width += this.adjustments[0];
53407 height += this.adjustments[1];
53409 return {"width": width, "height": height};
53412 setSize : function(width, height){
53413 if(this.fitToFrame && !this.ignoreResize(width, height)){
53414 if(this.fitContainer && this.resizeEl != this.el){
53415 this.el.setSize(width, height);
53417 var size = this.adjustForComponents(width, height);
53418 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53419 this.fireEvent('resize', this, size.width, size.height);
53424 * Returns this panel's title
53427 getTitle : function(){
53432 * Set this panel's title
53433 * @param {String} title
53435 setTitle : function(title){
53436 this.title = title;
53438 this.region.updatePanelTitle(this, title);
53443 * Returns true is this panel was configured to be closable
53444 * @return {Boolean}
53446 isClosable : function(){
53447 return this.closable;
53450 beforeSlide : function(){
53452 this.resizeEl.clip();
53455 afterSlide : function(){
53457 this.resizeEl.unclip();
53461 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53462 * Will fail silently if the {@link #setUrl} method has not been called.
53463 * This does not activate the panel, just updates its content.
53465 refresh : function(){
53466 if(this.refreshDelegate){
53467 this.loaded = false;
53468 this.refreshDelegate();
53473 * Destroys this panel
53475 destroy : function(){
53476 this.el.removeAllListeners();
53477 var tempEl = document.createElement("span");
53478 tempEl.appendChild(this.el.dom);
53479 tempEl.innerHTML = "";
53485 * form - if the content panel contains a form - this is a reference to it.
53486 * @type {Roo.form.Form}
53490 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53491 * This contains a reference to it.
53497 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53507 * @param {Object} cfg Xtype definition of item to add.
53510 addxtype : function(cfg) {
53512 if (cfg.xtype.match(/^Form$/)) {
53515 //if (this.footer) {
53516 // el = this.footer.container.insertSibling(false, 'before');
53518 el = this.el.createChild();
53521 this.form = new Roo.form.Form(cfg);
53524 if ( this.form.allItems.length) {
53525 this.form.render(el.dom);
53529 // should only have one of theses..
53530 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53531 // views.. should not be just added - used named prop 'view''
53533 cfg.el = this.el.appendChild(document.createElement("div"));
53536 var ret = new Roo.factory(cfg);
53538 ret.render && ret.render(false, ''); // render blank..
53547 * @class Roo.GridPanel
53548 * @extends Roo.ContentPanel
53550 * Create a new GridPanel.
53551 * @param {Roo.grid.Grid} grid The grid for this panel
53552 * @param {String/Object} config A string to set only the panel's title, or a config object
53554 Roo.GridPanel = function(grid, config){
53557 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53558 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53560 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53562 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53565 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53567 // xtype created footer. - not sure if will work as we normally have to render first..
53568 if (this.footer && !this.footer.el && this.footer.xtype) {
53570 this.footer.container = this.grid.getView().getFooterPanel(true);
53571 this.footer.dataSource = this.grid.dataSource;
53572 this.footer = Roo.factory(this.footer, Roo);
53576 grid.monitorWindowResize = false; // turn off autosizing
53577 grid.autoHeight = false;
53578 grid.autoWidth = false;
53580 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53583 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53584 getId : function(){
53585 return this.grid.id;
53589 * Returns the grid for this panel
53590 * @return {Roo.grid.Grid}
53592 getGrid : function(){
53596 setSize : function(width, height){
53597 if(!this.ignoreResize(width, height)){
53598 var grid = this.grid;
53599 var size = this.adjustForComponents(width, height);
53600 grid.getGridEl().setSize(size.width, size.height);
53605 beforeSlide : function(){
53606 this.grid.getView().scroller.clip();
53609 afterSlide : function(){
53610 this.grid.getView().scroller.unclip();
53613 destroy : function(){
53614 this.grid.destroy();
53616 Roo.GridPanel.superclass.destroy.call(this);
53622 * @class Roo.NestedLayoutPanel
53623 * @extends Roo.ContentPanel
53625 * Create a new NestedLayoutPanel.
53628 * @param {Roo.BorderLayout} layout The layout for this panel
53629 * @param {String/Object} config A string to set only the title or a config object
53631 Roo.NestedLayoutPanel = function(layout, config)
53633 // construct with only one argument..
53634 /* FIXME - implement nicer consturctors
53635 if (layout.layout) {
53637 layout = config.layout;
53638 delete config.layout;
53640 if (layout.xtype && !layout.getEl) {
53641 // then layout needs constructing..
53642 layout = Roo.factory(layout, Roo);
53647 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53649 layout.monitorWindowResize = false; // turn off autosizing
53650 this.layout = layout;
53651 this.layout.getEl().addClass("x-layout-nested-layout");
53658 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53660 setSize : function(width, height){
53661 if(!this.ignoreResize(width, height)){
53662 var size = this.adjustForComponents(width, height);
53663 var el = this.layout.getEl();
53664 el.setSize(size.width, size.height);
53665 var touch = el.dom.offsetWidth;
53666 this.layout.layout();
53667 // ie requires a double layout on the first pass
53668 if(Roo.isIE && !this.initialized){
53669 this.initialized = true;
53670 this.layout.layout();
53675 // activate all subpanels if not currently active..
53677 setActiveState : function(active){
53678 this.active = active;
53680 this.fireEvent("deactivate", this);
53684 this.fireEvent("activate", this);
53685 // not sure if this should happen before or after..
53686 if (!this.layout) {
53687 return; // should not happen..
53690 for (var r in this.layout.regions) {
53691 reg = this.layout.getRegion(r);
53692 if (reg.getActivePanel()) {
53693 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53694 reg.setActivePanel(reg.getActivePanel());
53697 if (!reg.panels.length) {
53700 reg.showPanel(reg.getPanel(0));
53709 * Returns the nested BorderLayout for this panel
53710 * @return {Roo.BorderLayout}
53712 getLayout : function(){
53713 return this.layout;
53717 * Adds a xtype elements to the layout of the nested panel
53721 xtype : 'ContentPanel',
53728 xtype : 'NestedLayoutPanel',
53734 items : [ ... list of content panels or nested layout panels.. ]
53738 * @param {Object} cfg Xtype definition of item to add.
53740 addxtype : function(cfg) {
53741 return this.layout.addxtype(cfg);
53746 Roo.ScrollPanel = function(el, config, content){
53747 config = config || {};
53748 config.fitToFrame = true;
53749 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53751 this.el.dom.style.overflow = "hidden";
53752 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53753 this.el.removeClass("x-layout-inactive-content");
53754 this.el.on("mousewheel", this.onWheel, this);
53756 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53757 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53758 up.unselectable(); down.unselectable();
53759 up.on("click", this.scrollUp, this);
53760 down.on("click", this.scrollDown, this);
53761 up.addClassOnOver("x-scroller-btn-over");
53762 down.addClassOnOver("x-scroller-btn-over");
53763 up.addClassOnClick("x-scroller-btn-click");
53764 down.addClassOnClick("x-scroller-btn-click");
53765 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53767 this.resizeEl = this.el;
53768 this.el = wrap; this.up = up; this.down = down;
53771 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53773 wheelIncrement : 5,
53774 scrollUp : function(){
53775 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53778 scrollDown : function(){
53779 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53782 afterScroll : function(){
53783 var el = this.resizeEl;
53784 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53785 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53786 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53789 setSize : function(){
53790 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53791 this.afterScroll();
53794 onWheel : function(e){
53795 var d = e.getWheelDelta();
53796 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53797 this.afterScroll();
53801 setContent : function(content, loadScripts){
53802 this.resizeEl.update(content, loadScripts);
53816 * @class Roo.TreePanel
53817 * @extends Roo.ContentPanel
53819 * Create a new TreePanel. - defaults to fit/scoll contents.
53820 * @param {String/Object} config A string to set only the panel's title, or a config object
53821 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53823 Roo.TreePanel = function(config){
53824 var el = config.el;
53825 var tree = config.tree;
53826 delete config.tree;
53827 delete config.el; // hopefull!
53829 // wrapper for IE7 strict & safari scroll issue
53831 var treeEl = el.createChild();
53832 config.resizeEl = treeEl;
53836 Roo.TreePanel.superclass.constructor.call(this, el, config);
53839 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53840 //console.log(tree);
53841 this.on('activate', function()
53843 if (this.tree.rendered) {
53846 //console.log('render tree');
53847 this.tree.render();
53849 // this should not be needed.. - it's actually the 'el' that resizes?
53850 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53852 //this.on('resize', function (cp, w, h) {
53853 // this.tree.innerCt.setWidth(w);
53854 // this.tree.innerCt.setHeight(h);
53855 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53862 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53879 * Ext JS Library 1.1.1
53880 * Copyright(c) 2006-2007, Ext JS, LLC.
53882 * Originally Released Under LGPL - original licence link has changed is not relivant.
53885 * <script type="text/javascript">
53890 * @class Roo.ReaderLayout
53891 * @extends Roo.BorderLayout
53892 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53893 * center region containing two nested regions (a top one for a list view and one for item preview below),
53894 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53895 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53896 * expedites the setup of the overall layout and regions for this common application style.
53899 var reader = new Roo.ReaderLayout();
53900 var CP = Roo.ContentPanel; // shortcut for adding
53902 reader.beginUpdate();
53903 reader.add("north", new CP("north", "North"));
53904 reader.add("west", new CP("west", {title: "West"}));
53905 reader.add("east", new CP("east", {title: "East"}));
53907 reader.regions.listView.add(new CP("listView", "List"));
53908 reader.regions.preview.add(new CP("preview", "Preview"));
53909 reader.endUpdate();
53912 * Create a new ReaderLayout
53913 * @param {Object} config Configuration options
53914 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53915 * document.body if omitted)
53917 Roo.ReaderLayout = function(config, renderTo){
53918 var c = config || {size:{}};
53919 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53920 north: c.north !== false ? Roo.apply({
53924 }, c.north) : false,
53925 west: c.west !== false ? Roo.apply({
53933 margins:{left:5,right:0,bottom:5,top:5},
53934 cmargins:{left:5,right:5,bottom:5,top:5}
53935 }, c.west) : false,
53936 east: c.east !== false ? Roo.apply({
53944 margins:{left:0,right:5,bottom:5,top:5},
53945 cmargins:{left:5,right:5,bottom:5,top:5}
53946 }, c.east) : false,
53947 center: Roo.apply({
53948 tabPosition: 'top',
53952 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53956 this.el.addClass('x-reader');
53958 this.beginUpdate();
53960 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53961 south: c.preview !== false ? Roo.apply({
53968 cmargins:{top:5,left:0, right:0, bottom:0}
53969 }, c.preview) : false,
53970 center: Roo.apply({
53976 this.add('center', new Roo.NestedLayoutPanel(inner,
53977 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53981 this.regions.preview = inner.getRegion('south');
53982 this.regions.listView = inner.getRegion('center');
53985 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53987 * Ext JS Library 1.1.1
53988 * Copyright(c) 2006-2007, Ext JS, LLC.
53990 * Originally Released Under LGPL - original licence link has changed is not relivant.
53993 * <script type="text/javascript">
53997 * @class Roo.grid.Grid
53998 * @extends Roo.util.Observable
53999 * This class represents the primary interface of a component based grid control.
54000 * <br><br>Usage:<pre><code>
54001 var grid = new Roo.grid.Grid("my-container-id", {
54004 selModel: mySelectionModel,
54005 autoSizeColumns: true,
54006 monitorWindowResize: false,
54007 trackMouseOver: true
54012 * <b>Common Problems:</b><br/>
54013 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54014 * element will correct this<br/>
54015 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54016 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54017 * are unpredictable.<br/>
54018 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54019 * grid to calculate dimensions/offsets.<br/>
54021 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54022 * The container MUST have some type of size defined for the grid to fill. The container will be
54023 * automatically set to position relative if it isn't already.
54024 * @param {Object} config A config object that sets properties on this grid.
54026 Roo.grid.Grid = function(container, config){
54027 // initialize the container
54028 this.container = Roo.get(container);
54029 this.container.update("");
54030 this.container.setStyle("overflow", "hidden");
54031 this.container.addClass('x-grid-container');
54033 this.id = this.container.id;
54035 Roo.apply(this, config);
54036 // check and correct shorthanded configs
54038 this.dataSource = this.ds;
54042 this.colModel = this.cm;
54046 this.selModel = this.sm;
54050 if (this.selModel) {
54051 this.selModel = Roo.factory(this.selModel, Roo.grid);
54052 this.sm = this.selModel;
54053 this.sm.xmodule = this.xmodule || false;
54055 if (typeof(this.colModel.config) == 'undefined') {
54056 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54057 this.cm = this.colModel;
54058 this.cm.xmodule = this.xmodule || false;
54060 if (this.dataSource) {
54061 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54062 this.ds = this.dataSource;
54063 this.ds.xmodule = this.xmodule || false;
54070 this.container.setWidth(this.width);
54074 this.container.setHeight(this.height);
54081 * The raw click event for the entire grid.
54082 * @param {Roo.EventObject} e
54087 * The raw dblclick event for the entire grid.
54088 * @param {Roo.EventObject} e
54092 * @event contextmenu
54093 * The raw contextmenu event for the entire grid.
54094 * @param {Roo.EventObject} e
54096 "contextmenu" : true,
54099 * The raw mousedown event for the entire grid.
54100 * @param {Roo.EventObject} e
54102 "mousedown" : true,
54105 * The raw mouseup event for the entire grid.
54106 * @param {Roo.EventObject} e
54111 * The raw mouseover event for the entire grid.
54112 * @param {Roo.EventObject} e
54114 "mouseover" : true,
54117 * The raw mouseout event for the entire grid.
54118 * @param {Roo.EventObject} e
54123 * The raw keypress event for the entire grid.
54124 * @param {Roo.EventObject} e
54129 * The raw keydown event for the entire grid.
54130 * @param {Roo.EventObject} e
54138 * Fires when a cell is clicked
54139 * @param {Grid} this
54140 * @param {Number} rowIndex
54141 * @param {Number} columnIndex
54142 * @param {Roo.EventObject} e
54144 "cellclick" : true,
54146 * @event celldblclick
54147 * Fires when a cell is double clicked
54148 * @param {Grid} this
54149 * @param {Number} rowIndex
54150 * @param {Number} columnIndex
54151 * @param {Roo.EventObject} e
54153 "celldblclick" : true,
54156 * Fires when a row is clicked
54157 * @param {Grid} this
54158 * @param {Number} rowIndex
54159 * @param {Roo.EventObject} e
54163 * @event rowdblclick
54164 * Fires when a row is double clicked
54165 * @param {Grid} this
54166 * @param {Number} rowIndex
54167 * @param {Roo.EventObject} e
54169 "rowdblclick" : true,
54171 * @event headerclick
54172 * Fires when a header is clicked
54173 * @param {Grid} this
54174 * @param {Number} columnIndex
54175 * @param {Roo.EventObject} e
54177 "headerclick" : true,
54179 * @event headerdblclick
54180 * Fires when a header cell is double clicked
54181 * @param {Grid} this
54182 * @param {Number} columnIndex
54183 * @param {Roo.EventObject} e
54185 "headerdblclick" : true,
54187 * @event rowcontextmenu
54188 * Fires when a row is right clicked
54189 * @param {Grid} this
54190 * @param {Number} rowIndex
54191 * @param {Roo.EventObject} e
54193 "rowcontextmenu" : true,
54195 * @event cellcontextmenu
54196 * Fires when a cell is right clicked
54197 * @param {Grid} this
54198 * @param {Number} rowIndex
54199 * @param {Number} cellIndex
54200 * @param {Roo.EventObject} e
54202 "cellcontextmenu" : true,
54204 * @event headercontextmenu
54205 * Fires when a header is right clicked
54206 * @param {Grid} this
54207 * @param {Number} columnIndex
54208 * @param {Roo.EventObject} e
54210 "headercontextmenu" : true,
54212 * @event bodyscroll
54213 * Fires when the body element is scrolled
54214 * @param {Number} scrollLeft
54215 * @param {Number} scrollTop
54217 "bodyscroll" : true,
54219 * @event columnresize
54220 * Fires when the user resizes a column
54221 * @param {Number} columnIndex
54222 * @param {Number} newSize
54224 "columnresize" : true,
54226 * @event columnmove
54227 * Fires when the user moves a column
54228 * @param {Number} oldIndex
54229 * @param {Number} newIndex
54231 "columnmove" : true,
54234 * Fires when row(s) start being dragged
54235 * @param {Grid} this
54236 * @param {Roo.GridDD} dd The drag drop object
54237 * @param {event} e The raw browser event
54239 "startdrag" : true,
54242 * Fires when a drag operation is complete
54243 * @param {Grid} this
54244 * @param {Roo.GridDD} dd The drag drop object
54245 * @param {event} e The raw browser event
54250 * Fires when dragged row(s) are dropped on a valid DD target
54251 * @param {Grid} this
54252 * @param {Roo.GridDD} dd The drag drop object
54253 * @param {String} targetId The target drag drop object
54254 * @param {event} e The raw browser event
54259 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54260 * @param {Grid} this
54261 * @param {Roo.GridDD} dd The drag drop object
54262 * @param {String} targetId The target drag drop object
54263 * @param {event} e The raw browser event
54268 * Fires when the dragged row(s) first cross another DD target while being dragged
54269 * @param {Grid} this
54270 * @param {Roo.GridDD} dd The drag drop object
54271 * @param {String} targetId The target drag drop object
54272 * @param {event} e The raw browser event
54274 "dragenter" : true,
54277 * Fires when the dragged row(s) leave another DD target while being dragged
54278 * @param {Grid} this
54279 * @param {Roo.GridDD} dd The drag drop object
54280 * @param {String} targetId The target drag drop object
54281 * @param {event} e The raw browser event
54286 * Fires when a row is rendered, so you can change add a style to it.
54287 * @param {GridView} gridview The grid view
54288 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54294 * Fires when the grid is rendered
54295 * @param {Grid} grid
54300 Roo.grid.Grid.superclass.constructor.call(this);
54302 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54305 * @cfg {String} ddGroup - drag drop group.
54309 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54311 minColumnWidth : 25,
54314 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54315 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54316 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54318 autoSizeColumns : false,
54321 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54323 autoSizeHeaders : true,
54326 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54328 monitorWindowResize : true,
54331 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54332 * rows measured to get a columns size. Default is 0 (all rows).
54334 maxRowsToMeasure : 0,
54337 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54339 trackMouseOver : true,
54342 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54346 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54348 enableDragDrop : false,
54351 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54353 enableColumnMove : true,
54356 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54358 enableColumnHide : true,
54361 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54363 enableRowHeightSync : false,
54366 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54371 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54373 autoHeight : false,
54376 * @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.
54378 autoExpandColumn : false,
54381 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54384 autoExpandMin : 50,
54387 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54389 autoExpandMax : 1000,
54392 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54397 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54401 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54411 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54412 * of a fixed width. Default is false.
54415 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54418 * Called once after all setup has been completed and the grid is ready to be rendered.
54419 * @return {Roo.grid.Grid} this
54421 render : function()
54423 var c = this.container;
54424 // try to detect autoHeight/width mode
54425 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54426 this.autoHeight = true;
54428 var view = this.getView();
54431 c.on("click", this.onClick, this);
54432 c.on("dblclick", this.onDblClick, this);
54433 c.on("contextmenu", this.onContextMenu, this);
54434 c.on("keydown", this.onKeyDown, this);
54436 c.on("touchstart", this.onTouchStart, this);
54439 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54441 this.getSelectionModel().init(this);
54446 this.loadMask = new Roo.LoadMask(this.container,
54447 Roo.apply({store:this.dataSource}, this.loadMask));
54451 if (this.toolbar && this.toolbar.xtype) {
54452 this.toolbar.container = this.getView().getHeaderPanel(true);
54453 this.toolbar = new Roo.Toolbar(this.toolbar);
54455 if (this.footer && this.footer.xtype) {
54456 this.footer.dataSource = this.getDataSource();
54457 this.footer.container = this.getView().getFooterPanel(true);
54458 this.footer = Roo.factory(this.footer, Roo);
54460 if (this.dropTarget && this.dropTarget.xtype) {
54461 delete this.dropTarget.xtype;
54462 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54466 this.rendered = true;
54467 this.fireEvent('render', this);
54472 * Reconfigures the grid to use a different Store and Column Model.
54473 * The View will be bound to the new objects and refreshed.
54474 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54475 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54477 reconfigure : function(dataSource, colModel){
54479 this.loadMask.destroy();
54480 this.loadMask = new Roo.LoadMask(this.container,
54481 Roo.apply({store:dataSource}, this.loadMask));
54483 this.view.bind(dataSource, colModel);
54484 this.dataSource = dataSource;
54485 this.colModel = colModel;
54486 this.view.refresh(true);
54490 onKeyDown : function(e){
54491 this.fireEvent("keydown", e);
54495 * Destroy this grid.
54496 * @param {Boolean} removeEl True to remove the element
54498 destroy : function(removeEl, keepListeners){
54500 this.loadMask.destroy();
54502 var c = this.container;
54503 c.removeAllListeners();
54504 this.view.destroy();
54505 this.colModel.purgeListeners();
54506 if(!keepListeners){
54507 this.purgeListeners();
54510 if(removeEl === true){
54516 processEvent : function(name, e){
54517 // does this fire select???
54518 //Roo.log('grid:processEvent ' + name);
54520 if (name != 'touchstart' ) {
54521 this.fireEvent(name, e);
54524 var t = e.getTarget();
54526 var header = v.findHeaderIndex(t);
54527 if(header !== false){
54528 var ename = name == 'touchstart' ? 'click' : name;
54530 this.fireEvent("header" + ename, this, header, e);
54532 var row = v.findRowIndex(t);
54533 var cell = v.findCellIndex(t);
54534 if (name == 'touchstart') {
54535 // first touch is always a click.
54536 // hopefull this happens after selection is updated.?
54539 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54540 var cs = this.selModel.getSelectedCell();
54541 if (row == cs[0] && cell == cs[1]){
54545 if (typeof(this.selModel.getSelections) != 'undefined') {
54546 var cs = this.selModel.getSelections();
54547 var ds = this.dataSource;
54548 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54559 this.fireEvent("row" + name, this, row, e);
54560 if(cell !== false){
54561 this.fireEvent("cell" + name, this, row, cell, e);
54568 onClick : function(e){
54569 this.processEvent("click", e);
54572 onTouchStart : function(e){
54573 this.processEvent("touchstart", e);
54577 onContextMenu : function(e, t){
54578 this.processEvent("contextmenu", e);
54582 onDblClick : function(e){
54583 this.processEvent("dblclick", e);
54587 walkCells : function(row, col, step, fn, scope){
54588 var cm = this.colModel, clen = cm.getColumnCount();
54589 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54601 if(fn.call(scope || this, row, col, cm) === true){
54619 if(fn.call(scope || this, row, col, cm) === true){
54631 getSelections : function(){
54632 return this.selModel.getSelections();
54636 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54637 * but if manual update is required this method will initiate it.
54639 autoSize : function(){
54641 this.view.layout();
54642 if(this.view.adjustForScroll){
54643 this.view.adjustForScroll();
54649 * Returns the grid's underlying element.
54650 * @return {Element} The element
54652 getGridEl : function(){
54653 return this.container;
54656 // private for compatibility, overridden by editor grid
54657 stopEditing : function(){},
54660 * Returns the grid's SelectionModel.
54661 * @return {SelectionModel}
54663 getSelectionModel : function(){
54664 if(!this.selModel){
54665 this.selModel = new Roo.grid.RowSelectionModel();
54667 return this.selModel;
54671 * Returns the grid's DataSource.
54672 * @return {DataSource}
54674 getDataSource : function(){
54675 return this.dataSource;
54679 * Returns the grid's ColumnModel.
54680 * @return {ColumnModel}
54682 getColumnModel : function(){
54683 return this.colModel;
54687 * Returns the grid's GridView object.
54688 * @return {GridView}
54690 getView : function(){
54692 this.view = new Roo.grid.GridView(this.viewConfig);
54697 * Called to get grid's drag proxy text, by default returns this.ddText.
54700 getDragDropText : function(){
54701 var count = this.selModel.getCount();
54702 return String.format(this.ddText, count, count == 1 ? '' : 's');
54706 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54707 * %0 is replaced with the number of selected rows.
54710 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54712 * Ext JS Library 1.1.1
54713 * Copyright(c) 2006-2007, Ext JS, LLC.
54715 * Originally Released Under LGPL - original licence link has changed is not relivant.
54718 * <script type="text/javascript">
54721 Roo.grid.AbstractGridView = function(){
54725 "beforerowremoved" : true,
54726 "beforerowsinserted" : true,
54727 "beforerefresh" : true,
54728 "rowremoved" : true,
54729 "rowsinserted" : true,
54730 "rowupdated" : true,
54733 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54736 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54737 rowClass : "x-grid-row",
54738 cellClass : "x-grid-cell",
54739 tdClass : "x-grid-td",
54740 hdClass : "x-grid-hd",
54741 splitClass : "x-grid-hd-split",
54743 init: function(grid){
54745 var cid = this.grid.getGridEl().id;
54746 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54747 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54748 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54749 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54752 getColumnRenderers : function(){
54753 var renderers = [];
54754 var cm = this.grid.colModel;
54755 var colCount = cm.getColumnCount();
54756 for(var i = 0; i < colCount; i++){
54757 renderers[i] = cm.getRenderer(i);
54762 getColumnIds : function(){
54764 var cm = this.grid.colModel;
54765 var colCount = cm.getColumnCount();
54766 for(var i = 0; i < colCount; i++){
54767 ids[i] = cm.getColumnId(i);
54772 getDataIndexes : function(){
54773 if(!this.indexMap){
54774 this.indexMap = this.buildIndexMap();
54776 return this.indexMap.colToData;
54779 getColumnIndexByDataIndex : function(dataIndex){
54780 if(!this.indexMap){
54781 this.indexMap = this.buildIndexMap();
54783 return this.indexMap.dataToCol[dataIndex];
54787 * Set a css style for a column dynamically.
54788 * @param {Number} colIndex The index of the column
54789 * @param {String} name The css property name
54790 * @param {String} value The css value
54792 setCSSStyle : function(colIndex, name, value){
54793 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54794 Roo.util.CSS.updateRule(selector, name, value);
54797 generateRules : function(cm){
54798 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54799 Roo.util.CSS.removeStyleSheet(rulesId);
54800 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54801 var cid = cm.getColumnId(i);
54802 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54803 this.tdSelector, cid, " {\n}\n",
54804 this.hdSelector, cid, " {\n}\n",
54805 this.splitSelector, cid, " {\n}\n");
54807 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54811 * Ext JS Library 1.1.1
54812 * Copyright(c) 2006-2007, Ext JS, LLC.
54814 * Originally Released Under LGPL - original licence link has changed is not relivant.
54817 * <script type="text/javascript">
54821 // This is a support class used internally by the Grid components
54822 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54824 this.view = grid.getView();
54825 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54826 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54828 this.setHandleElId(Roo.id(hd));
54829 this.setOuterHandleElId(Roo.id(hd2));
54831 this.scroll = false;
54833 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54835 getDragData : function(e){
54836 var t = Roo.lib.Event.getTarget(e);
54837 var h = this.view.findHeaderCell(t);
54839 return {ddel: h.firstChild, header:h};
54844 onInitDrag : function(e){
54845 this.view.headersDisabled = true;
54846 var clone = this.dragData.ddel.cloneNode(true);
54847 clone.id = Roo.id();
54848 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54849 this.proxy.update(clone);
54853 afterValidDrop : function(){
54855 setTimeout(function(){
54856 v.headersDisabled = false;
54860 afterInvalidDrop : function(){
54862 setTimeout(function(){
54863 v.headersDisabled = false;
54869 * Ext JS Library 1.1.1
54870 * Copyright(c) 2006-2007, Ext JS, LLC.
54872 * Originally Released Under LGPL - original licence link has changed is not relivant.
54875 * <script type="text/javascript">
54878 // This is a support class used internally by the Grid components
54879 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54881 this.view = grid.getView();
54882 // split the proxies so they don't interfere with mouse events
54883 this.proxyTop = Roo.DomHelper.append(document.body, {
54884 cls:"col-move-top", html:" "
54886 this.proxyBottom = Roo.DomHelper.append(document.body, {
54887 cls:"col-move-bottom", html:" "
54889 this.proxyTop.hide = this.proxyBottom.hide = function(){
54890 this.setLeftTop(-100,-100);
54891 this.setStyle("visibility", "hidden");
54893 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54894 // temporarily disabled
54895 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54896 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54898 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54899 proxyOffsets : [-4, -9],
54900 fly: Roo.Element.fly,
54902 getTargetFromEvent : function(e){
54903 var t = Roo.lib.Event.getTarget(e);
54904 var cindex = this.view.findCellIndex(t);
54905 if(cindex !== false){
54906 return this.view.getHeaderCell(cindex);
54911 nextVisible : function(h){
54912 var v = this.view, cm = this.grid.colModel;
54915 if(!cm.isHidden(v.getCellIndex(h))){
54923 prevVisible : function(h){
54924 var v = this.view, cm = this.grid.colModel;
54927 if(!cm.isHidden(v.getCellIndex(h))){
54935 positionIndicator : function(h, n, e){
54936 var x = Roo.lib.Event.getPageX(e);
54937 var r = Roo.lib.Dom.getRegion(n.firstChild);
54938 var px, pt, py = r.top + this.proxyOffsets[1];
54939 if((r.right - x) <= (r.right-r.left)/2){
54940 px = r.right+this.view.borderWidth;
54946 var oldIndex = this.view.getCellIndex(h);
54947 var newIndex = this.view.getCellIndex(n);
54949 if(this.grid.colModel.isFixed(newIndex)){
54953 var locked = this.grid.colModel.isLocked(newIndex);
54958 if(oldIndex < newIndex){
54961 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54964 px += this.proxyOffsets[0];
54965 this.proxyTop.setLeftTop(px, py);
54966 this.proxyTop.show();
54967 if(!this.bottomOffset){
54968 this.bottomOffset = this.view.mainHd.getHeight();
54970 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54971 this.proxyBottom.show();
54975 onNodeEnter : function(n, dd, e, data){
54976 if(data.header != n){
54977 this.positionIndicator(data.header, n, e);
54981 onNodeOver : function(n, dd, e, data){
54982 var result = false;
54983 if(data.header != n){
54984 result = this.positionIndicator(data.header, n, e);
54987 this.proxyTop.hide();
54988 this.proxyBottom.hide();
54990 return result ? this.dropAllowed : this.dropNotAllowed;
54993 onNodeOut : function(n, dd, e, data){
54994 this.proxyTop.hide();
54995 this.proxyBottom.hide();
54998 onNodeDrop : function(n, dd, e, data){
54999 var h = data.header;
55001 var cm = this.grid.colModel;
55002 var x = Roo.lib.Event.getPageX(e);
55003 var r = Roo.lib.Dom.getRegion(n.firstChild);
55004 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55005 var oldIndex = this.view.getCellIndex(h);
55006 var newIndex = this.view.getCellIndex(n);
55007 var locked = cm.isLocked(newIndex);
55011 if(oldIndex < newIndex){
55014 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55017 cm.setLocked(oldIndex, locked, true);
55018 cm.moveColumn(oldIndex, newIndex);
55019 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55027 * Ext JS Library 1.1.1
55028 * Copyright(c) 2006-2007, Ext JS, LLC.
55030 * Originally Released Under LGPL - original licence link has changed is not relivant.
55033 * <script type="text/javascript">
55037 * @class Roo.grid.GridView
55038 * @extends Roo.util.Observable
55041 * @param {Object} config
55043 Roo.grid.GridView = function(config){
55044 Roo.grid.GridView.superclass.constructor.call(this);
55047 Roo.apply(this, config);
55050 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55052 unselectable : 'unselectable="on"',
55053 unselectableCls : 'x-unselectable',
55056 rowClass : "x-grid-row",
55058 cellClass : "x-grid-col",
55060 tdClass : "x-grid-td",
55062 hdClass : "x-grid-hd",
55064 splitClass : "x-grid-split",
55066 sortClasses : ["sort-asc", "sort-desc"],
55068 enableMoveAnim : false,
55072 dh : Roo.DomHelper,
55074 fly : Roo.Element.fly,
55076 css : Roo.util.CSS,
55082 scrollIncrement : 22,
55084 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55086 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55088 bind : function(ds, cm){
55090 this.ds.un("load", this.onLoad, this);
55091 this.ds.un("datachanged", this.onDataChange, this);
55092 this.ds.un("add", this.onAdd, this);
55093 this.ds.un("remove", this.onRemove, this);
55094 this.ds.un("update", this.onUpdate, this);
55095 this.ds.un("clear", this.onClear, this);
55098 ds.on("load", this.onLoad, this);
55099 ds.on("datachanged", this.onDataChange, this);
55100 ds.on("add", this.onAdd, this);
55101 ds.on("remove", this.onRemove, this);
55102 ds.on("update", this.onUpdate, this);
55103 ds.on("clear", this.onClear, this);
55108 this.cm.un("widthchange", this.onColWidthChange, this);
55109 this.cm.un("headerchange", this.onHeaderChange, this);
55110 this.cm.un("hiddenchange", this.onHiddenChange, this);
55111 this.cm.un("columnmoved", this.onColumnMove, this);
55112 this.cm.un("columnlockchange", this.onColumnLock, this);
55115 this.generateRules(cm);
55116 cm.on("widthchange", this.onColWidthChange, this);
55117 cm.on("headerchange", this.onHeaderChange, this);
55118 cm.on("hiddenchange", this.onHiddenChange, this);
55119 cm.on("columnmoved", this.onColumnMove, this);
55120 cm.on("columnlockchange", this.onColumnLock, this);
55125 init: function(grid){
55126 Roo.grid.GridView.superclass.init.call(this, grid);
55128 this.bind(grid.dataSource, grid.colModel);
55130 grid.on("headerclick", this.handleHeaderClick, this);
55132 if(grid.trackMouseOver){
55133 grid.on("mouseover", this.onRowOver, this);
55134 grid.on("mouseout", this.onRowOut, this);
55136 grid.cancelTextSelection = function(){};
55137 this.gridId = grid.id;
55139 var tpls = this.templates || {};
55142 tpls.master = new Roo.Template(
55143 '<div class="x-grid" hidefocus="true">',
55144 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55145 '<div class="x-grid-topbar"></div>',
55146 '<div class="x-grid-scroller"><div></div></div>',
55147 '<div class="x-grid-locked">',
55148 '<div class="x-grid-header">{lockedHeader}</div>',
55149 '<div class="x-grid-body">{lockedBody}</div>',
55151 '<div class="x-grid-viewport">',
55152 '<div class="x-grid-header">{header}</div>',
55153 '<div class="x-grid-body">{body}</div>',
55155 '<div class="x-grid-bottombar"></div>',
55157 '<div class="x-grid-resize-proxy"> </div>',
55160 tpls.master.disableformats = true;
55164 tpls.header = new Roo.Template(
55165 '<table border="0" cellspacing="0" cellpadding="0">',
55166 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55169 tpls.header.disableformats = true;
55171 tpls.header.compile();
55174 tpls.hcell = new Roo.Template(
55175 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55176 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55179 tpls.hcell.disableFormats = true;
55181 tpls.hcell.compile();
55184 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55185 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55186 tpls.hsplit.disableFormats = true;
55188 tpls.hsplit.compile();
55191 tpls.body = new Roo.Template(
55192 '<table border="0" cellspacing="0" cellpadding="0">',
55193 "<tbody>{rows}</tbody>",
55196 tpls.body.disableFormats = true;
55198 tpls.body.compile();
55201 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55202 tpls.row.disableFormats = true;
55204 tpls.row.compile();
55207 tpls.cell = new Roo.Template(
55208 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55209 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55210 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55213 tpls.cell.disableFormats = true;
55215 tpls.cell.compile();
55217 this.templates = tpls;
55220 // remap these for backwards compat
55221 onColWidthChange : function(){
55222 this.updateColumns.apply(this, arguments);
55224 onHeaderChange : function(){
55225 this.updateHeaders.apply(this, arguments);
55227 onHiddenChange : function(){
55228 this.handleHiddenChange.apply(this, arguments);
55230 onColumnMove : function(){
55231 this.handleColumnMove.apply(this, arguments);
55233 onColumnLock : function(){
55234 this.handleLockChange.apply(this, arguments);
55237 onDataChange : function(){
55239 this.updateHeaderSortState();
55242 onClear : function(){
55246 onUpdate : function(ds, record){
55247 this.refreshRow(record);
55250 refreshRow : function(record){
55251 var ds = this.ds, index;
55252 if(typeof record == 'number'){
55254 record = ds.getAt(index);
55256 index = ds.indexOf(record);
55258 this.insertRows(ds, index, index, true);
55259 this.onRemove(ds, record, index+1, true);
55260 this.syncRowHeights(index, index);
55262 this.fireEvent("rowupdated", this, index, record);
55265 onAdd : function(ds, records, index){
55266 this.insertRows(ds, index, index + (records.length-1));
55269 onRemove : function(ds, record, index, isUpdate){
55270 if(isUpdate !== true){
55271 this.fireEvent("beforerowremoved", this, index, record);
55273 var bt = this.getBodyTable(), lt = this.getLockedTable();
55274 if(bt.rows[index]){
55275 bt.firstChild.removeChild(bt.rows[index]);
55277 if(lt.rows[index]){
55278 lt.firstChild.removeChild(lt.rows[index]);
55280 if(isUpdate !== true){
55281 this.stripeRows(index);
55282 this.syncRowHeights(index, index);
55284 this.fireEvent("rowremoved", this, index, record);
55288 onLoad : function(){
55289 this.scrollToTop();
55293 * Scrolls the grid to the top
55295 scrollToTop : function(){
55297 this.scroller.dom.scrollTop = 0;
55303 * Gets a panel in the header of the grid that can be used for toolbars etc.
55304 * After modifying the contents of this panel a call to grid.autoSize() may be
55305 * required to register any changes in size.
55306 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55307 * @return Roo.Element
55309 getHeaderPanel : function(doShow){
55311 this.headerPanel.show();
55313 return this.headerPanel;
55317 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55318 * After modifying the contents of this panel a call to grid.autoSize() may be
55319 * required to register any changes in size.
55320 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55321 * @return Roo.Element
55323 getFooterPanel : function(doShow){
55325 this.footerPanel.show();
55327 return this.footerPanel;
55330 initElements : function(){
55331 var E = Roo.Element;
55332 var el = this.grid.getGridEl().dom.firstChild;
55333 var cs = el.childNodes;
55335 this.el = new E(el);
55337 this.focusEl = new E(el.firstChild);
55338 this.focusEl.swallowEvent("click", true);
55340 this.headerPanel = new E(cs[1]);
55341 this.headerPanel.enableDisplayMode("block");
55343 this.scroller = new E(cs[2]);
55344 this.scrollSizer = new E(this.scroller.dom.firstChild);
55346 this.lockedWrap = new E(cs[3]);
55347 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55348 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55350 this.mainWrap = new E(cs[4]);
55351 this.mainHd = new E(this.mainWrap.dom.firstChild);
55352 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55354 this.footerPanel = new E(cs[5]);
55355 this.footerPanel.enableDisplayMode("block");
55357 this.resizeProxy = new E(cs[6]);
55359 this.headerSelector = String.format(
55360 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55361 this.lockedHd.id, this.mainHd.id
55364 this.splitterSelector = String.format(
55365 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55366 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55369 idToCssName : function(s)
55371 return s.replace(/[^a-z0-9]+/ig, '-');
55374 getHeaderCell : function(index){
55375 return Roo.DomQuery.select(this.headerSelector)[index];
55378 getHeaderCellMeasure : function(index){
55379 return this.getHeaderCell(index).firstChild;
55382 getHeaderCellText : function(index){
55383 return this.getHeaderCell(index).firstChild.firstChild;
55386 getLockedTable : function(){
55387 return this.lockedBody.dom.firstChild;
55390 getBodyTable : function(){
55391 return this.mainBody.dom.firstChild;
55394 getLockedRow : function(index){
55395 return this.getLockedTable().rows[index];
55398 getRow : function(index){
55399 return this.getBodyTable().rows[index];
55402 getRowComposite : function(index){
55404 this.rowEl = new Roo.CompositeElementLite();
55406 var els = [], lrow, mrow;
55407 if(lrow = this.getLockedRow(index)){
55410 if(mrow = this.getRow(index)){
55413 this.rowEl.elements = els;
55417 * Gets the 'td' of the cell
55419 * @param {Integer} rowIndex row to select
55420 * @param {Integer} colIndex column to select
55424 getCell : function(rowIndex, colIndex){
55425 var locked = this.cm.getLockedCount();
55427 if(colIndex < locked){
55428 source = this.lockedBody.dom.firstChild;
55430 source = this.mainBody.dom.firstChild;
55431 colIndex -= locked;
55433 return source.rows[rowIndex].childNodes[colIndex];
55436 getCellText : function(rowIndex, colIndex){
55437 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55440 getCellBox : function(cell){
55441 var b = this.fly(cell).getBox();
55442 if(Roo.isOpera){ // opera fails to report the Y
55443 b.y = cell.offsetTop + this.mainBody.getY();
55448 getCellIndex : function(cell){
55449 var id = String(cell.className).match(this.cellRE);
55451 return parseInt(id[1], 10);
55456 findHeaderIndex : function(n){
55457 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55458 return r ? this.getCellIndex(r) : false;
55461 findHeaderCell : function(n){
55462 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55463 return r ? r : false;
55466 findRowIndex : function(n){
55470 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55471 return r ? r.rowIndex : false;
55474 findCellIndex : function(node){
55475 var stop = this.el.dom;
55476 while(node && node != stop){
55477 if(this.findRE.test(node.className)){
55478 return this.getCellIndex(node);
55480 node = node.parentNode;
55485 getColumnId : function(index){
55486 return this.cm.getColumnId(index);
55489 getSplitters : function()
55491 if(this.splitterSelector){
55492 return Roo.DomQuery.select(this.splitterSelector);
55498 getSplitter : function(index){
55499 return this.getSplitters()[index];
55502 onRowOver : function(e, t){
55504 if((row = this.findRowIndex(t)) !== false){
55505 this.getRowComposite(row).addClass("x-grid-row-over");
55509 onRowOut : function(e, t){
55511 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55512 this.getRowComposite(row).removeClass("x-grid-row-over");
55516 renderHeaders : function(){
55518 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55519 var cb = [], lb = [], sb = [], lsb = [], p = {};
55520 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55521 p.cellId = "x-grid-hd-0-" + i;
55522 p.splitId = "x-grid-csplit-0-" + i;
55523 p.id = cm.getColumnId(i);
55524 p.value = cm.getColumnHeader(i) || "";
55525 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55526 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55527 if(!cm.isLocked(i)){
55528 cb[cb.length] = ct.apply(p);
55529 sb[sb.length] = st.apply(p);
55531 lb[lb.length] = ct.apply(p);
55532 lsb[lsb.length] = st.apply(p);
55535 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55536 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55539 updateHeaders : function(){
55540 var html = this.renderHeaders();
55541 this.lockedHd.update(html[0]);
55542 this.mainHd.update(html[1]);
55546 * Focuses the specified row.
55547 * @param {Number} row The row index
55549 focusRow : function(row)
55551 //Roo.log('GridView.focusRow');
55552 var x = this.scroller.dom.scrollLeft;
55553 this.focusCell(row, 0, false);
55554 this.scroller.dom.scrollLeft = x;
55558 * Focuses the specified cell.
55559 * @param {Number} row The row index
55560 * @param {Number} col The column index
55561 * @param {Boolean} hscroll false to disable horizontal scrolling
55563 focusCell : function(row, col, hscroll)
55565 //Roo.log('GridView.focusCell');
55566 var el = this.ensureVisible(row, col, hscroll);
55567 this.focusEl.alignTo(el, "tl-tl");
55569 this.focusEl.focus();
55571 this.focusEl.focus.defer(1, this.focusEl);
55576 * Scrolls the specified cell into view
55577 * @param {Number} row The row index
55578 * @param {Number} col The column index
55579 * @param {Boolean} hscroll false to disable horizontal scrolling
55581 ensureVisible : function(row, col, hscroll)
55583 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55584 //return null; //disable for testing.
55585 if(typeof row != "number"){
55586 row = row.rowIndex;
55588 if(row < 0 && row >= this.ds.getCount()){
55591 col = (col !== undefined ? col : 0);
55592 var cm = this.grid.colModel;
55593 while(cm.isHidden(col)){
55597 var el = this.getCell(row, col);
55601 var c = this.scroller.dom;
55603 var ctop = parseInt(el.offsetTop, 10);
55604 var cleft = parseInt(el.offsetLeft, 10);
55605 var cbot = ctop + el.offsetHeight;
55606 var cright = cleft + el.offsetWidth;
55608 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55609 var stop = parseInt(c.scrollTop, 10);
55610 var sleft = parseInt(c.scrollLeft, 10);
55611 var sbot = stop + ch;
55612 var sright = sleft + c.clientWidth;
55614 Roo.log('GridView.ensureVisible:' +
55616 ' c.clientHeight:' + c.clientHeight +
55617 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55625 c.scrollTop = ctop;
55626 //Roo.log("set scrolltop to ctop DISABLE?");
55627 }else if(cbot > sbot){
55628 //Roo.log("set scrolltop to cbot-ch");
55629 c.scrollTop = cbot-ch;
55632 if(hscroll !== false){
55634 c.scrollLeft = cleft;
55635 }else if(cright > sright){
55636 c.scrollLeft = cright-c.clientWidth;
55643 updateColumns : function(){
55644 this.grid.stopEditing();
55645 var cm = this.grid.colModel, colIds = this.getColumnIds();
55646 //var totalWidth = cm.getTotalWidth();
55648 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55649 //if(cm.isHidden(i)) continue;
55650 var w = cm.getColumnWidth(i);
55651 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55652 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55654 this.updateSplitters();
55657 generateRules : function(cm){
55658 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55659 Roo.util.CSS.removeStyleSheet(rulesId);
55660 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55661 var cid = cm.getColumnId(i);
55663 if(cm.config[i].align){
55664 align = 'text-align:'+cm.config[i].align+';';
55667 if(cm.isHidden(i)){
55668 hidden = 'display:none;';
55670 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55672 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55673 this.hdSelector, cid, " {\n", align, width, "}\n",
55674 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55675 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55677 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55680 updateSplitters : function(){
55681 var cm = this.cm, s = this.getSplitters();
55682 if(s){ // splitters not created yet
55683 var pos = 0, locked = true;
55684 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55685 if(cm.isHidden(i)) {
55688 var w = cm.getColumnWidth(i); // make sure it's a number
55689 if(!cm.isLocked(i) && locked){
55694 s[i].style.left = (pos-this.splitOffset) + "px";
55699 handleHiddenChange : function(colModel, colIndex, hidden){
55701 this.hideColumn(colIndex);
55703 this.unhideColumn(colIndex);
55707 hideColumn : function(colIndex){
55708 var cid = this.getColumnId(colIndex);
55709 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55710 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55712 this.updateHeaders();
55714 this.updateSplitters();
55718 unhideColumn : function(colIndex){
55719 var cid = this.getColumnId(colIndex);
55720 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55721 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55724 this.updateHeaders();
55726 this.updateSplitters();
55730 insertRows : function(dm, firstRow, lastRow, isUpdate){
55731 if(firstRow == 0 && lastRow == dm.getCount()-1){
55735 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55737 var s = this.getScrollState();
55738 var markup = this.renderRows(firstRow, lastRow);
55739 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55740 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55741 this.restoreScroll(s);
55743 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55744 this.syncRowHeights(firstRow, lastRow);
55745 this.stripeRows(firstRow);
55751 bufferRows : function(markup, target, index){
55752 var before = null, trows = target.rows, tbody = target.tBodies[0];
55753 if(index < trows.length){
55754 before = trows[index];
55756 var b = document.createElement("div");
55757 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55758 var rows = b.firstChild.rows;
55759 for(var i = 0, len = rows.length; i < len; i++){
55761 tbody.insertBefore(rows[0], before);
55763 tbody.appendChild(rows[0]);
55770 deleteRows : function(dm, firstRow, lastRow){
55771 if(dm.getRowCount()<1){
55772 this.fireEvent("beforerefresh", this);
55773 this.mainBody.update("");
55774 this.lockedBody.update("");
55775 this.fireEvent("refresh", this);
55777 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55778 var bt = this.getBodyTable();
55779 var tbody = bt.firstChild;
55780 var rows = bt.rows;
55781 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55782 tbody.removeChild(rows[firstRow]);
55784 this.stripeRows(firstRow);
55785 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55789 updateRows : function(dataSource, firstRow, lastRow){
55790 var s = this.getScrollState();
55792 this.restoreScroll(s);
55795 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55799 this.updateHeaderSortState();
55802 getScrollState : function(){
55804 var sb = this.scroller.dom;
55805 return {left: sb.scrollLeft, top: sb.scrollTop};
55808 stripeRows : function(startRow){
55809 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55812 startRow = startRow || 0;
55813 var rows = this.getBodyTable().rows;
55814 var lrows = this.getLockedTable().rows;
55815 var cls = ' x-grid-row-alt ';
55816 for(var i = startRow, len = rows.length; i < len; i++){
55817 var row = rows[i], lrow = lrows[i];
55818 var isAlt = ((i+1) % 2 == 0);
55819 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55820 if(isAlt == hasAlt){
55824 row.className += " x-grid-row-alt";
55826 row.className = row.className.replace("x-grid-row-alt", "");
55829 lrow.className = row.className;
55834 restoreScroll : function(state){
55835 //Roo.log('GridView.restoreScroll');
55836 var sb = this.scroller.dom;
55837 sb.scrollLeft = state.left;
55838 sb.scrollTop = state.top;
55842 syncScroll : function(){
55843 //Roo.log('GridView.syncScroll');
55844 var sb = this.scroller.dom;
55845 var sh = this.mainHd.dom;
55846 var bs = this.mainBody.dom;
55847 var lv = this.lockedBody.dom;
55848 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55849 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55852 handleScroll : function(e){
55854 var sb = this.scroller.dom;
55855 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55859 handleWheel : function(e){
55860 var d = e.getWheelDelta();
55861 this.scroller.dom.scrollTop -= d*22;
55862 // set this here to prevent jumpy scrolling on large tables
55863 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55867 renderRows : function(startRow, endRow){
55868 // pull in all the crap needed to render rows
55869 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55870 var colCount = cm.getColumnCount();
55872 if(ds.getCount() < 1){
55876 // build a map for all the columns
55878 for(var i = 0; i < colCount; i++){
55879 var name = cm.getDataIndex(i);
55881 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55882 renderer : cm.getRenderer(i),
55883 id : cm.getColumnId(i),
55884 locked : cm.isLocked(i),
55885 has_editor : cm.isCellEditable(i)
55889 startRow = startRow || 0;
55890 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55892 // records to render
55893 var rs = ds.getRange(startRow, endRow);
55895 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55898 // As much as I hate to duplicate code, this was branched because FireFox really hates
55899 // [].join("") on strings. The performance difference was substantial enough to
55900 // branch this function
55901 doRender : Roo.isGecko ?
55902 function(cs, rs, ds, startRow, colCount, stripe){
55903 var ts = this.templates, ct = ts.cell, rt = ts.row;
55905 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55907 var hasListener = this.grid.hasListener('rowclass');
55909 for(var j = 0, len = rs.length; j < len; j++){
55910 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55911 for(var i = 0; i < colCount; i++){
55913 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55915 p.css = p.attr = "";
55916 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55917 if(p.value == undefined || p.value === "") {
55918 p.value = " ";
55921 p.css += ' x-grid-editable-cell';
55923 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55924 p.css += ' x-grid-dirty-cell';
55926 var markup = ct.apply(p);
55934 if(stripe && ((rowIndex+1) % 2 == 0)){
55935 alt.push("x-grid-row-alt")
55938 alt.push( " x-grid-dirty-row");
55941 if(this.getRowClass){
55942 alt.push(this.getRowClass(r, rowIndex));
55948 rowIndex : rowIndex,
55951 this.grid.fireEvent('rowclass', this, rowcfg);
55952 alt.push(rowcfg.rowClass);
55954 rp.alt = alt.join(" ");
55955 lbuf+= rt.apply(rp);
55957 buf+= rt.apply(rp);
55959 return [lbuf, buf];
55961 function(cs, rs, ds, startRow, colCount, stripe){
55962 var ts = this.templates, ct = ts.cell, rt = ts.row;
55964 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55965 var hasListener = this.grid.hasListener('rowclass');
55968 for(var j = 0, len = rs.length; j < len; j++){
55969 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55970 for(var i = 0; i < colCount; i++){
55972 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55974 p.css = p.attr = "";
55975 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55976 if(p.value == undefined || p.value === "") {
55977 p.value = " ";
55981 p.css += ' x-grid-editable-cell';
55983 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55984 p.css += ' x-grid-dirty-cell'
55987 var markup = ct.apply(p);
55989 cb[cb.length] = markup;
55991 lcb[lcb.length] = markup;
55995 if(stripe && ((rowIndex+1) % 2 == 0)){
55996 alt.push( "x-grid-row-alt");
55999 alt.push(" x-grid-dirty-row");
56002 if(this.getRowClass){
56003 alt.push( this.getRowClass(r, rowIndex));
56009 rowIndex : rowIndex,
56012 this.grid.fireEvent('rowclass', this, rowcfg);
56013 alt.push(rowcfg.rowClass);
56016 rp.alt = alt.join(" ");
56017 rp.cells = lcb.join("");
56018 lbuf[lbuf.length] = rt.apply(rp);
56019 rp.cells = cb.join("");
56020 buf[buf.length] = rt.apply(rp);
56022 return [lbuf.join(""), buf.join("")];
56025 renderBody : function(){
56026 var markup = this.renderRows();
56027 var bt = this.templates.body;
56028 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56032 * Refreshes the grid
56033 * @param {Boolean} headersToo
56035 refresh : function(headersToo){
56036 this.fireEvent("beforerefresh", this);
56037 this.grid.stopEditing();
56038 var result = this.renderBody();
56039 this.lockedBody.update(result[0]);
56040 this.mainBody.update(result[1]);
56041 if(headersToo === true){
56042 this.updateHeaders();
56043 this.updateColumns();
56044 this.updateSplitters();
56045 this.updateHeaderSortState();
56047 this.syncRowHeights();
56049 this.fireEvent("refresh", this);
56052 handleColumnMove : function(cm, oldIndex, newIndex){
56053 this.indexMap = null;
56054 var s = this.getScrollState();
56055 this.refresh(true);
56056 this.restoreScroll(s);
56057 this.afterMove(newIndex);
56060 afterMove : function(colIndex){
56061 if(this.enableMoveAnim && Roo.enableFx){
56062 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56064 // if multisort - fix sortOrder, and reload..
56065 if (this.grid.dataSource.multiSort) {
56066 // the we can call sort again..
56067 var dm = this.grid.dataSource;
56068 var cm = this.grid.colModel;
56070 for(var i = 0; i < cm.config.length; i++ ) {
56072 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56073 continue; // dont' bother, it's not in sort list or being set.
56076 so.push(cm.config[i].dataIndex);
56079 dm.load(dm.lastOptions);
56086 updateCell : function(dm, rowIndex, dataIndex){
56087 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56088 if(typeof colIndex == "undefined"){ // not present in grid
56091 var cm = this.grid.colModel;
56092 var cell = this.getCell(rowIndex, colIndex);
56093 var cellText = this.getCellText(rowIndex, colIndex);
56096 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56097 id : cm.getColumnId(colIndex),
56098 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56100 var renderer = cm.getRenderer(colIndex);
56101 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56102 if(typeof val == "undefined" || val === "") {
56105 cellText.innerHTML = val;
56106 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56107 this.syncRowHeights(rowIndex, rowIndex);
56110 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56112 if(this.grid.autoSizeHeaders){
56113 var h = this.getHeaderCellMeasure(colIndex);
56114 maxWidth = Math.max(maxWidth, h.scrollWidth);
56117 if(this.cm.isLocked(colIndex)){
56118 tb = this.getLockedTable();
56121 tb = this.getBodyTable();
56122 index = colIndex - this.cm.getLockedCount();
56125 var rows = tb.rows;
56126 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56127 for(var i = 0; i < stopIndex; i++){
56128 var cell = rows[i].childNodes[index].firstChild;
56129 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56132 return maxWidth + /*margin for error in IE*/ 5;
56135 * Autofit a column to its content.
56136 * @param {Number} colIndex
56137 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56139 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56140 if(this.cm.isHidden(colIndex)){
56141 return; // can't calc a hidden column
56144 var cid = this.cm.getColumnId(colIndex);
56145 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56146 if(this.grid.autoSizeHeaders){
56147 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56150 var newWidth = this.calcColumnWidth(colIndex);
56151 this.cm.setColumnWidth(colIndex,
56152 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56153 if(!suppressEvent){
56154 this.grid.fireEvent("columnresize", colIndex, newWidth);
56159 * Autofits all columns to their content and then expands to fit any extra space in the grid
56161 autoSizeColumns : function(){
56162 var cm = this.grid.colModel;
56163 var colCount = cm.getColumnCount();
56164 for(var i = 0; i < colCount; i++){
56165 this.autoSizeColumn(i, true, true);
56167 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56170 this.updateColumns();
56176 * Autofits all columns to the grid's width proportionate with their current size
56177 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56179 fitColumns : function(reserveScrollSpace){
56180 var cm = this.grid.colModel;
56181 var colCount = cm.getColumnCount();
56185 for (i = 0; i < colCount; i++){
56186 if(!cm.isHidden(i) && !cm.isFixed(i)){
56187 w = cm.getColumnWidth(i);
56193 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56194 if(reserveScrollSpace){
56197 var frac = (avail - cm.getTotalWidth())/width;
56198 while (cols.length){
56201 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56203 this.updateColumns();
56207 onRowSelect : function(rowIndex){
56208 var row = this.getRowComposite(rowIndex);
56209 row.addClass("x-grid-row-selected");
56212 onRowDeselect : function(rowIndex){
56213 var row = this.getRowComposite(rowIndex);
56214 row.removeClass("x-grid-row-selected");
56217 onCellSelect : function(row, col){
56218 var cell = this.getCell(row, col);
56220 Roo.fly(cell).addClass("x-grid-cell-selected");
56224 onCellDeselect : function(row, col){
56225 var cell = this.getCell(row, col);
56227 Roo.fly(cell).removeClass("x-grid-cell-selected");
56231 updateHeaderSortState : function(){
56233 // sort state can be single { field: xxx, direction : yyy}
56234 // or { xxx=>ASC , yyy : DESC ..... }
56237 if (!this.ds.multiSort) {
56238 var state = this.ds.getSortState();
56242 mstate[state.field] = state.direction;
56243 // FIXME... - this is not used here.. but might be elsewhere..
56244 this.sortState = state;
56247 mstate = this.ds.sortToggle;
56249 //remove existing sort classes..
56251 var sc = this.sortClasses;
56252 var hds = this.el.select(this.headerSelector).removeClass(sc);
56254 for(var f in mstate) {
56256 var sortColumn = this.cm.findColumnIndex(f);
56258 if(sortColumn != -1){
56259 var sortDir = mstate[f];
56260 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56269 handleHeaderClick : function(g, index,e){
56271 Roo.log("header click");
56274 // touch events on header are handled by context
56275 this.handleHdCtx(g,index,e);
56280 if(this.headersDisabled){
56283 var dm = g.dataSource, cm = g.colModel;
56284 if(!cm.isSortable(index)){
56289 if (dm.multiSort) {
56290 // update the sortOrder
56292 for(var i = 0; i < cm.config.length; i++ ) {
56294 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56295 continue; // dont' bother, it's not in sort list or being set.
56298 so.push(cm.config[i].dataIndex);
56304 dm.sort(cm.getDataIndex(index));
56308 destroy : function(){
56310 this.colMenu.removeAll();
56311 Roo.menu.MenuMgr.unregister(this.colMenu);
56312 this.colMenu.getEl().remove();
56313 delete this.colMenu;
56316 this.hmenu.removeAll();
56317 Roo.menu.MenuMgr.unregister(this.hmenu);
56318 this.hmenu.getEl().remove();
56321 if(this.grid.enableColumnMove){
56322 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56324 for(var dd in dds){
56325 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56326 var elid = dds[dd].dragElId;
56328 Roo.get(elid).remove();
56329 } else if(dds[dd].config.isTarget){
56330 dds[dd].proxyTop.remove();
56331 dds[dd].proxyBottom.remove();
56334 if(Roo.dd.DDM.locationCache[dd]){
56335 delete Roo.dd.DDM.locationCache[dd];
56338 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56341 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56342 this.bind(null, null);
56343 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56346 handleLockChange : function(){
56347 this.refresh(true);
56350 onDenyColumnLock : function(){
56354 onDenyColumnHide : function(){
56358 handleHdMenuClick : function(item){
56359 var index = this.hdCtxIndex;
56360 var cm = this.cm, ds = this.ds;
56363 ds.sort(cm.getDataIndex(index), "ASC");
56366 ds.sort(cm.getDataIndex(index), "DESC");
56369 var lc = cm.getLockedCount();
56370 if(cm.getColumnCount(true) <= lc+1){
56371 this.onDenyColumnLock();
56375 cm.setLocked(index, true, true);
56376 cm.moveColumn(index, lc);
56377 this.grid.fireEvent("columnmove", index, lc);
56379 cm.setLocked(index, true);
56383 var lc = cm.getLockedCount();
56384 if((lc-1) != index){
56385 cm.setLocked(index, false, true);
56386 cm.moveColumn(index, lc-1);
56387 this.grid.fireEvent("columnmove", index, lc-1);
56389 cm.setLocked(index, false);
56392 case 'wider': // used to expand cols on touch..
56394 var cw = cm.getColumnWidth(index);
56395 cw += (item.id == 'wider' ? 1 : -1) * 50;
56396 cw = Math.max(0, cw);
56397 cw = Math.min(cw,4000);
56398 cm.setColumnWidth(index, cw);
56402 index = cm.getIndexById(item.id.substr(4));
56404 if(item.checked && cm.getColumnCount(true) <= 1){
56405 this.onDenyColumnHide();
56408 cm.setHidden(index, item.checked);
56414 beforeColMenuShow : function(){
56415 var cm = this.cm, colCount = cm.getColumnCount();
56416 this.colMenu.removeAll();
56417 for(var i = 0; i < colCount; i++){
56418 this.colMenu.add(new Roo.menu.CheckItem({
56419 id: "col-"+cm.getColumnId(i),
56420 text: cm.getColumnHeader(i),
56421 checked: !cm.isHidden(i),
56427 handleHdCtx : function(g, index, e){
56429 var hd = this.getHeaderCell(index);
56430 this.hdCtxIndex = index;
56431 var ms = this.hmenu.items, cm = this.cm;
56432 ms.get("asc").setDisabled(!cm.isSortable(index));
56433 ms.get("desc").setDisabled(!cm.isSortable(index));
56434 if(this.grid.enableColLock !== false){
56435 ms.get("lock").setDisabled(cm.isLocked(index));
56436 ms.get("unlock").setDisabled(!cm.isLocked(index));
56438 this.hmenu.show(hd, "tl-bl");
56441 handleHdOver : function(e){
56442 var hd = this.findHeaderCell(e.getTarget());
56443 if(hd && !this.headersDisabled){
56444 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56445 this.fly(hd).addClass("x-grid-hd-over");
56450 handleHdOut : function(e){
56451 var hd = this.findHeaderCell(e.getTarget());
56453 this.fly(hd).removeClass("x-grid-hd-over");
56457 handleSplitDblClick : function(e, t){
56458 var i = this.getCellIndex(t);
56459 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56460 this.autoSizeColumn(i, true);
56465 render : function(){
56468 var colCount = cm.getColumnCount();
56470 if(this.grid.monitorWindowResize === true){
56471 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56473 var header = this.renderHeaders();
56474 var body = this.templates.body.apply({rows:""});
56475 var html = this.templates.master.apply({
56478 lockedHeader: header[0],
56482 //this.updateColumns();
56484 this.grid.getGridEl().dom.innerHTML = html;
56486 this.initElements();
56488 // a kludge to fix the random scolling effect in webkit
56489 this.el.on("scroll", function() {
56490 this.el.dom.scrollTop=0; // hopefully not recursive..
56493 this.scroller.on("scroll", this.handleScroll, this);
56494 this.lockedBody.on("mousewheel", this.handleWheel, this);
56495 this.mainBody.on("mousewheel", this.handleWheel, this);
56497 this.mainHd.on("mouseover", this.handleHdOver, this);
56498 this.mainHd.on("mouseout", this.handleHdOut, this);
56499 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56500 {delegate: "."+this.splitClass});
56502 this.lockedHd.on("mouseover", this.handleHdOver, this);
56503 this.lockedHd.on("mouseout", this.handleHdOut, this);
56504 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56505 {delegate: "."+this.splitClass});
56507 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56508 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56511 this.updateSplitters();
56513 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56514 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56515 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56518 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56519 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56521 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56522 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56524 if(this.grid.enableColLock !== false){
56525 this.hmenu.add('-',
56526 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56527 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56531 this.hmenu.add('-',
56532 {id:"wider", text: this.columnsWiderText},
56533 {id:"narrow", text: this.columnsNarrowText }
56539 if(this.grid.enableColumnHide !== false){
56541 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56542 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56543 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56545 this.hmenu.add('-',
56546 {id:"columns", text: this.columnsText, menu: this.colMenu}
56549 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56551 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56554 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56555 this.dd = new Roo.grid.GridDragZone(this.grid, {
56556 ddGroup : this.grid.ddGroup || 'GridDD'
56562 for(var i = 0; i < colCount; i++){
56563 if(cm.isHidden(i)){
56564 this.hideColumn(i);
56566 if(cm.config[i].align){
56567 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56568 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56572 this.updateHeaderSortState();
56574 this.beforeInitialResize();
56577 // two part rendering gives faster view to the user
56578 this.renderPhase2.defer(1, this);
56581 renderPhase2 : function(){
56582 // render the rows now
56584 if(this.grid.autoSizeColumns){
56585 this.autoSizeColumns();
56589 beforeInitialResize : function(){
56593 onColumnSplitterMoved : function(i, w){
56594 this.userResized = true;
56595 var cm = this.grid.colModel;
56596 cm.setColumnWidth(i, w, true);
56597 var cid = cm.getColumnId(i);
56598 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56599 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56600 this.updateSplitters();
56602 this.grid.fireEvent("columnresize", i, w);
56605 syncRowHeights : function(startIndex, endIndex){
56606 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56607 startIndex = startIndex || 0;
56608 var mrows = this.getBodyTable().rows;
56609 var lrows = this.getLockedTable().rows;
56610 var len = mrows.length-1;
56611 endIndex = Math.min(endIndex || len, len);
56612 for(var i = startIndex; i <= endIndex; i++){
56613 var m = mrows[i], l = lrows[i];
56614 var h = Math.max(m.offsetHeight, l.offsetHeight);
56615 m.style.height = l.style.height = h + "px";
56620 layout : function(initialRender, is2ndPass){
56622 var auto = g.autoHeight;
56623 var scrollOffset = 16;
56624 var c = g.getGridEl(), cm = this.cm,
56625 expandCol = g.autoExpandColumn,
56627 //c.beginMeasure();
56629 if(!c.dom.offsetWidth){ // display:none?
56631 this.lockedWrap.show();
56632 this.mainWrap.show();
56637 var hasLock = this.cm.isLocked(0);
56639 var tbh = this.headerPanel.getHeight();
56640 var bbh = this.footerPanel.getHeight();
56643 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56644 var newHeight = ch + c.getBorderWidth("tb");
56646 newHeight = Math.min(g.maxHeight, newHeight);
56648 c.setHeight(newHeight);
56652 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56655 var s = this.scroller;
56657 var csize = c.getSize(true);
56659 this.el.setSize(csize.width, csize.height);
56661 this.headerPanel.setWidth(csize.width);
56662 this.footerPanel.setWidth(csize.width);
56664 var hdHeight = this.mainHd.getHeight();
56665 var vw = csize.width;
56666 var vh = csize.height - (tbh + bbh);
56670 var bt = this.getBodyTable();
56672 if(cm.getLockedCount() == cm.config.length){
56673 bt = this.getLockedTable();
56676 var ltWidth = hasLock ?
56677 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56679 var scrollHeight = bt.offsetHeight;
56680 var scrollWidth = ltWidth + bt.offsetWidth;
56681 var vscroll = false, hscroll = false;
56683 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56685 var lw = this.lockedWrap, mw = this.mainWrap;
56686 var lb = this.lockedBody, mb = this.mainBody;
56688 setTimeout(function(){
56689 var t = s.dom.offsetTop;
56690 var w = s.dom.clientWidth,
56691 h = s.dom.clientHeight;
56694 lw.setSize(ltWidth, h);
56696 mw.setLeftTop(ltWidth, t);
56697 mw.setSize(w-ltWidth, h);
56699 lb.setHeight(h-hdHeight);
56700 mb.setHeight(h-hdHeight);
56702 if(is2ndPass !== true && !gv.userResized && expandCol){
56703 // high speed resize without full column calculation
56705 var ci = cm.getIndexById(expandCol);
56707 ci = cm.findColumnIndex(expandCol);
56709 ci = Math.max(0, ci); // make sure it's got at least the first col.
56710 var expandId = cm.getColumnId(ci);
56711 var tw = cm.getTotalWidth(false);
56712 var currentWidth = cm.getColumnWidth(ci);
56713 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56714 if(currentWidth != cw){
56715 cm.setColumnWidth(ci, cw, true);
56716 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56717 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56718 gv.updateSplitters();
56719 gv.layout(false, true);
56731 onWindowResize : function(){
56732 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56738 appendFooter : function(parentEl){
56742 sortAscText : "Sort Ascending",
56743 sortDescText : "Sort Descending",
56744 lockText : "Lock Column",
56745 unlockText : "Unlock Column",
56746 columnsText : "Columns",
56748 columnsWiderText : "Wider",
56749 columnsNarrowText : "Thinner"
56753 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56754 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56755 this.proxy.el.addClass('x-grid3-col-dd');
56758 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56759 handleMouseDown : function(e){
56763 callHandleMouseDown : function(e){
56764 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56769 * Ext JS Library 1.1.1
56770 * Copyright(c) 2006-2007, Ext JS, LLC.
56772 * Originally Released Under LGPL - original licence link has changed is not relivant.
56775 * <script type="text/javascript">
56779 // This is a support class used internally by the Grid components
56780 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56782 this.view = grid.getView();
56783 this.proxy = this.view.resizeProxy;
56784 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56785 "gridSplitters" + this.grid.getGridEl().id, {
56786 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56788 this.setHandleElId(Roo.id(hd));
56789 this.setOuterHandleElId(Roo.id(hd2));
56790 this.scroll = false;
56792 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56793 fly: Roo.Element.fly,
56795 b4StartDrag : function(x, y){
56796 this.view.headersDisabled = true;
56797 this.proxy.setHeight(this.view.mainWrap.getHeight());
56798 var w = this.cm.getColumnWidth(this.cellIndex);
56799 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56800 this.resetConstraints();
56801 this.setXConstraint(minw, 1000);
56802 this.setYConstraint(0, 0);
56803 this.minX = x - minw;
56804 this.maxX = x + 1000;
56806 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56810 handleMouseDown : function(e){
56811 ev = Roo.EventObject.setEvent(e);
56812 var t = this.fly(ev.getTarget());
56813 if(t.hasClass("x-grid-split")){
56814 this.cellIndex = this.view.getCellIndex(t.dom);
56815 this.split = t.dom;
56816 this.cm = this.grid.colModel;
56817 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56818 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56823 endDrag : function(e){
56824 this.view.headersDisabled = false;
56825 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56826 var diff = endX - this.startPos;
56827 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56830 autoOffset : function(){
56831 this.setDelta(0,0);
56835 * Ext JS Library 1.1.1
56836 * Copyright(c) 2006-2007, Ext JS, LLC.
56838 * Originally Released Under LGPL - original licence link has changed is not relivant.
56841 * <script type="text/javascript">
56845 // This is a support class used internally by the Grid components
56846 Roo.grid.GridDragZone = function(grid, config){
56847 this.view = grid.getView();
56848 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56849 if(this.view.lockedBody){
56850 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56851 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56853 this.scroll = false;
56855 this.ddel = document.createElement('div');
56856 this.ddel.className = 'x-grid-dd-wrap';
56859 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56860 ddGroup : "GridDD",
56862 getDragData : function(e){
56863 var t = Roo.lib.Event.getTarget(e);
56864 var rowIndex = this.view.findRowIndex(t);
56865 var sm = this.grid.selModel;
56867 //Roo.log(rowIndex);
56869 if (sm.getSelectedCell) {
56870 // cell selection..
56871 if (!sm.getSelectedCell()) {
56874 if (rowIndex != sm.getSelectedCell()[0]) {
56880 if(rowIndex !== false){
56885 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56887 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56890 if (e.hasModifier()){
56891 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56894 Roo.log("getDragData");
56899 rowIndex: rowIndex,
56900 selections:sm.getSelections ? sm.getSelections() : (
56901 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56908 onInitDrag : function(e){
56909 var data = this.dragData;
56910 this.ddel.innerHTML = this.grid.getDragDropText();
56911 this.proxy.update(this.ddel);
56912 // fire start drag?
56915 afterRepair : function(){
56916 this.dragging = false;
56919 getRepairXY : function(e, data){
56923 onEndDrag : function(data, e){
56927 onValidDrop : function(dd, e, id){
56932 beforeInvalidDrop : function(e, id){
56937 * Ext JS Library 1.1.1
56938 * Copyright(c) 2006-2007, Ext JS, LLC.
56940 * Originally Released Under LGPL - original licence link has changed is not relivant.
56943 * <script type="text/javascript">
56948 * @class Roo.grid.ColumnModel
56949 * @extends Roo.util.Observable
56950 * This is the default implementation of a ColumnModel used by the Grid. It defines
56951 * the columns in the grid.
56954 var colModel = new Roo.grid.ColumnModel([
56955 {header: "Ticker", width: 60, sortable: true, locked: true},
56956 {header: "Company Name", width: 150, sortable: true},
56957 {header: "Market Cap.", width: 100, sortable: true},
56958 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56959 {header: "Employees", width: 100, sortable: true, resizable: false}
56964 * The config options listed for this class are options which may appear in each
56965 * individual column definition.
56966 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56968 * @param {Object} config An Array of column config objects. See this class's
56969 * config objects for details.
56971 Roo.grid.ColumnModel = function(config){
56973 * The config passed into the constructor
56975 this.config = config;
56978 // if no id, create one
56979 // if the column does not have a dataIndex mapping,
56980 // map it to the order it is in the config
56981 for(var i = 0, len = config.length; i < len; i++){
56983 if(typeof c.dataIndex == "undefined"){
56986 if(typeof c.renderer == "string"){
56987 c.renderer = Roo.util.Format[c.renderer];
56989 if(typeof c.id == "undefined"){
56992 if(c.editor && c.editor.xtype){
56993 c.editor = Roo.factory(c.editor, Roo.grid);
56995 if(c.editor && c.editor.isFormField){
56996 c.editor = new Roo.grid.GridEditor(c.editor);
56998 this.lookup[c.id] = c;
57002 * The width of columns which have no width specified (defaults to 100)
57005 this.defaultWidth = 100;
57008 * Default sortable of columns which have no sortable specified (defaults to false)
57011 this.defaultSortable = false;
57015 * @event widthchange
57016 * Fires when the width of a column changes.
57017 * @param {ColumnModel} this
57018 * @param {Number} columnIndex The column index
57019 * @param {Number} newWidth The new width
57021 "widthchange": true,
57023 * @event headerchange
57024 * Fires when the text of a header changes.
57025 * @param {ColumnModel} this
57026 * @param {Number} columnIndex The column index
57027 * @param {Number} newText The new header text
57029 "headerchange": true,
57031 * @event hiddenchange
57032 * Fires when a column is hidden or "unhidden".
57033 * @param {ColumnModel} this
57034 * @param {Number} columnIndex The column index
57035 * @param {Boolean} hidden true if hidden, false otherwise
57037 "hiddenchange": true,
57039 * @event columnmoved
57040 * Fires when a column is moved.
57041 * @param {ColumnModel} this
57042 * @param {Number} oldIndex
57043 * @param {Number} newIndex
57045 "columnmoved" : true,
57047 * @event columlockchange
57048 * Fires when a column's locked state is changed
57049 * @param {ColumnModel} this
57050 * @param {Number} colIndex
57051 * @param {Boolean} locked true if locked
57053 "columnlockchange" : true
57055 Roo.grid.ColumnModel.superclass.constructor.call(this);
57057 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57059 * @cfg {String} header The header text to display in the Grid view.
57062 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57063 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57064 * specified, the column's index is used as an index into the Record's data Array.
57067 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57068 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57071 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57072 * Defaults to the value of the {@link #defaultSortable} property.
57073 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57076 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57079 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57082 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57085 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57088 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57089 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57090 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57091 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57094 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57097 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57100 * @cfg {String} cursor (Optional)
57103 * @cfg {String} tooltip (Optional)
57106 * @cfg {Number} xs (Optional)
57109 * @cfg {Number} sm (Optional)
57112 * @cfg {Number} md (Optional)
57115 * @cfg {Number} lg (Optional)
57118 * Returns the id of the column at the specified index.
57119 * @param {Number} index The column index
57120 * @return {String} the id
57122 getColumnId : function(index){
57123 return this.config[index].id;
57127 * Returns the column for a specified id.
57128 * @param {String} id The column id
57129 * @return {Object} the column
57131 getColumnById : function(id){
57132 return this.lookup[id];
57137 * Returns the column for a specified dataIndex.
57138 * @param {String} dataIndex The column dataIndex
57139 * @return {Object|Boolean} the column or false if not found
57141 getColumnByDataIndex: function(dataIndex){
57142 var index = this.findColumnIndex(dataIndex);
57143 return index > -1 ? this.config[index] : false;
57147 * Returns the index for a specified column id.
57148 * @param {String} id The column id
57149 * @return {Number} the index, or -1 if not found
57151 getIndexById : function(id){
57152 for(var i = 0, len = this.config.length; i < len; i++){
57153 if(this.config[i].id == id){
57161 * Returns the index for a specified column dataIndex.
57162 * @param {String} dataIndex The column dataIndex
57163 * @return {Number} the index, or -1 if not found
57166 findColumnIndex : function(dataIndex){
57167 for(var i = 0, len = this.config.length; i < len; i++){
57168 if(this.config[i].dataIndex == dataIndex){
57176 moveColumn : function(oldIndex, newIndex){
57177 var c = this.config[oldIndex];
57178 this.config.splice(oldIndex, 1);
57179 this.config.splice(newIndex, 0, c);
57180 this.dataMap = null;
57181 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57184 isLocked : function(colIndex){
57185 return this.config[colIndex].locked === true;
57188 setLocked : function(colIndex, value, suppressEvent){
57189 if(this.isLocked(colIndex) == value){
57192 this.config[colIndex].locked = value;
57193 if(!suppressEvent){
57194 this.fireEvent("columnlockchange", this, colIndex, value);
57198 getTotalLockedWidth : function(){
57199 var totalWidth = 0;
57200 for(var i = 0; i < this.config.length; i++){
57201 if(this.isLocked(i) && !this.isHidden(i)){
57202 this.totalWidth += this.getColumnWidth(i);
57208 getLockedCount : function(){
57209 for(var i = 0, len = this.config.length; i < len; i++){
57210 if(!this.isLocked(i)){
57215 return this.config.length;
57219 * Returns the number of columns.
57222 getColumnCount : function(visibleOnly){
57223 if(visibleOnly === true){
57225 for(var i = 0, len = this.config.length; i < len; i++){
57226 if(!this.isHidden(i)){
57232 return this.config.length;
57236 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57237 * @param {Function} fn
57238 * @param {Object} scope (optional)
57239 * @return {Array} result
57241 getColumnsBy : function(fn, scope){
57243 for(var i = 0, len = this.config.length; i < len; i++){
57244 var c = this.config[i];
57245 if(fn.call(scope||this, c, i) === true){
57253 * Returns true if the specified column is sortable.
57254 * @param {Number} col The column index
57255 * @return {Boolean}
57257 isSortable : function(col){
57258 if(typeof this.config[col].sortable == "undefined"){
57259 return this.defaultSortable;
57261 return this.config[col].sortable;
57265 * Returns the rendering (formatting) function defined for the column.
57266 * @param {Number} col The column index.
57267 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57269 getRenderer : function(col){
57270 if(!this.config[col].renderer){
57271 return Roo.grid.ColumnModel.defaultRenderer;
57273 return this.config[col].renderer;
57277 * Sets the rendering (formatting) function for a column.
57278 * @param {Number} col The column index
57279 * @param {Function} fn The function to use to process the cell's raw data
57280 * to return HTML markup for the grid view. The render function is called with
57281 * the following parameters:<ul>
57282 * <li>Data value.</li>
57283 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57284 * <li>css A CSS style string to apply to the table cell.</li>
57285 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57286 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57287 * <li>Row index</li>
57288 * <li>Column index</li>
57289 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57291 setRenderer : function(col, fn){
57292 this.config[col].renderer = fn;
57296 * Returns the width for the specified column.
57297 * @param {Number} col The column index
57300 getColumnWidth : function(col){
57301 return this.config[col].width * 1 || this.defaultWidth;
57305 * Sets the width for a column.
57306 * @param {Number} col The column index
57307 * @param {Number} width The new width
57309 setColumnWidth : function(col, width, suppressEvent){
57310 this.config[col].width = width;
57311 this.totalWidth = null;
57312 if(!suppressEvent){
57313 this.fireEvent("widthchange", this, col, width);
57318 * Returns the total width of all columns.
57319 * @param {Boolean} includeHidden True to include hidden column widths
57322 getTotalWidth : function(includeHidden){
57323 if(!this.totalWidth){
57324 this.totalWidth = 0;
57325 for(var i = 0, len = this.config.length; i < len; i++){
57326 if(includeHidden || !this.isHidden(i)){
57327 this.totalWidth += this.getColumnWidth(i);
57331 return this.totalWidth;
57335 * Returns the header for the specified column.
57336 * @param {Number} col The column index
57339 getColumnHeader : function(col){
57340 return this.config[col].header;
57344 * Sets the header for a column.
57345 * @param {Number} col The column index
57346 * @param {String} header The new header
57348 setColumnHeader : function(col, header){
57349 this.config[col].header = header;
57350 this.fireEvent("headerchange", this, col, header);
57354 * Returns the tooltip for the specified column.
57355 * @param {Number} col The column index
57358 getColumnTooltip : function(col){
57359 return this.config[col].tooltip;
57362 * Sets the tooltip for a column.
57363 * @param {Number} col The column index
57364 * @param {String} tooltip The new tooltip
57366 setColumnTooltip : function(col, tooltip){
57367 this.config[col].tooltip = tooltip;
57371 * Returns the dataIndex for the specified column.
57372 * @param {Number} col The column index
57375 getDataIndex : function(col){
57376 return this.config[col].dataIndex;
57380 * Sets the dataIndex for a column.
57381 * @param {Number} col The column index
57382 * @param {Number} dataIndex The new dataIndex
57384 setDataIndex : function(col, dataIndex){
57385 this.config[col].dataIndex = dataIndex;
57391 * Returns true if the cell is editable.
57392 * @param {Number} colIndex The column index
57393 * @param {Number} rowIndex The row index - this is nto actually used..?
57394 * @return {Boolean}
57396 isCellEditable : function(colIndex, rowIndex){
57397 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57401 * Returns the editor defined for the cell/column.
57402 * return false or null to disable editing.
57403 * @param {Number} colIndex The column index
57404 * @param {Number} rowIndex The row index
57407 getCellEditor : function(colIndex, rowIndex){
57408 return this.config[colIndex].editor;
57412 * Sets if a column is editable.
57413 * @param {Number} col The column index
57414 * @param {Boolean} editable True if the column is editable
57416 setEditable : function(col, editable){
57417 this.config[col].editable = editable;
57422 * Returns true if the column is hidden.
57423 * @param {Number} colIndex The column index
57424 * @return {Boolean}
57426 isHidden : function(colIndex){
57427 return this.config[colIndex].hidden;
57432 * Returns true if the column width cannot be changed
57434 isFixed : function(colIndex){
57435 return this.config[colIndex].fixed;
57439 * Returns true if the column can be resized
57440 * @return {Boolean}
57442 isResizable : function(colIndex){
57443 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57446 * Sets if a column is hidden.
57447 * @param {Number} colIndex The column index
57448 * @param {Boolean} hidden True if the column is hidden
57450 setHidden : function(colIndex, hidden){
57451 this.config[colIndex].hidden = hidden;
57452 this.totalWidth = null;
57453 this.fireEvent("hiddenchange", this, colIndex, hidden);
57457 * Sets the editor for a column.
57458 * @param {Number} col The column index
57459 * @param {Object} editor The editor object
57461 setEditor : function(col, editor){
57462 this.config[col].editor = editor;
57466 Roo.grid.ColumnModel.defaultRenderer = function(value)
57468 if(typeof value == "object") {
57471 if(typeof value == "string" && value.length < 1){
57475 return String.format("{0}", value);
57478 // Alias for backwards compatibility
57479 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57482 * Ext JS Library 1.1.1
57483 * Copyright(c) 2006-2007, Ext JS, LLC.
57485 * Originally Released Under LGPL - original licence link has changed is not relivant.
57488 * <script type="text/javascript">
57492 * @class Roo.grid.AbstractSelectionModel
57493 * @extends Roo.util.Observable
57494 * Abstract base class for grid SelectionModels. It provides the interface that should be
57495 * implemented by descendant classes. This class should not be directly instantiated.
57498 Roo.grid.AbstractSelectionModel = function(){
57499 this.locked = false;
57500 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57503 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57504 /** @ignore Called by the grid automatically. Do not call directly. */
57505 init : function(grid){
57511 * Locks the selections.
57514 this.locked = true;
57518 * Unlocks the selections.
57520 unlock : function(){
57521 this.locked = false;
57525 * Returns true if the selections are locked.
57526 * @return {Boolean}
57528 isLocked : function(){
57529 return this.locked;
57533 * Ext JS Library 1.1.1
57534 * Copyright(c) 2006-2007, Ext JS, LLC.
57536 * Originally Released Under LGPL - original licence link has changed is not relivant.
57539 * <script type="text/javascript">
57542 * @extends Roo.grid.AbstractSelectionModel
57543 * @class Roo.grid.RowSelectionModel
57544 * The default SelectionModel used by {@link Roo.grid.Grid}.
57545 * It supports multiple selections and keyboard selection/navigation.
57547 * @param {Object} config
57549 Roo.grid.RowSelectionModel = function(config){
57550 Roo.apply(this, config);
57551 this.selections = new Roo.util.MixedCollection(false, function(o){
57556 this.lastActive = false;
57560 * @event selectionchange
57561 * Fires when the selection changes
57562 * @param {SelectionModel} this
57564 "selectionchange" : true,
57566 * @event afterselectionchange
57567 * Fires after the selection changes (eg. by key press or clicking)
57568 * @param {SelectionModel} this
57570 "afterselectionchange" : true,
57572 * @event beforerowselect
57573 * Fires when a row is selected being selected, return false to cancel.
57574 * @param {SelectionModel} this
57575 * @param {Number} rowIndex The selected index
57576 * @param {Boolean} keepExisting False if other selections will be cleared
57578 "beforerowselect" : true,
57581 * Fires when a row is selected.
57582 * @param {SelectionModel} this
57583 * @param {Number} rowIndex The selected index
57584 * @param {Roo.data.Record} r The record
57586 "rowselect" : true,
57588 * @event rowdeselect
57589 * Fires when a row is deselected.
57590 * @param {SelectionModel} this
57591 * @param {Number} rowIndex The selected index
57593 "rowdeselect" : true
57595 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57596 this.locked = false;
57599 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57601 * @cfg {Boolean} singleSelect
57602 * True to allow selection of only one row at a time (defaults to false)
57604 singleSelect : false,
57607 initEvents : function(){
57609 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57610 this.grid.on("mousedown", this.handleMouseDown, this);
57611 }else{ // allow click to work like normal
57612 this.grid.on("rowclick", this.handleDragableRowClick, this);
57615 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57616 "up" : function(e){
57618 this.selectPrevious(e.shiftKey);
57619 }else if(this.last !== false && this.lastActive !== false){
57620 var last = this.last;
57621 this.selectRange(this.last, this.lastActive-1);
57622 this.grid.getView().focusRow(this.lastActive);
57623 if(last !== false){
57627 this.selectFirstRow();
57629 this.fireEvent("afterselectionchange", this);
57631 "down" : function(e){
57633 this.selectNext(e.shiftKey);
57634 }else if(this.last !== false && this.lastActive !== false){
57635 var last = this.last;
57636 this.selectRange(this.last, this.lastActive+1);
57637 this.grid.getView().focusRow(this.lastActive);
57638 if(last !== false){
57642 this.selectFirstRow();
57644 this.fireEvent("afterselectionchange", this);
57649 var view = this.grid.view;
57650 view.on("refresh", this.onRefresh, this);
57651 view.on("rowupdated", this.onRowUpdated, this);
57652 view.on("rowremoved", this.onRemove, this);
57656 onRefresh : function(){
57657 var ds = this.grid.dataSource, i, v = this.grid.view;
57658 var s = this.selections;
57659 s.each(function(r){
57660 if((i = ds.indexOfId(r.id)) != -1){
57662 s.add(ds.getAt(i)); // updating the selection relate data
57670 onRemove : function(v, index, r){
57671 this.selections.remove(r);
57675 onRowUpdated : function(v, index, r){
57676 if(this.isSelected(r)){
57677 v.onRowSelect(index);
57683 * @param {Array} records The records to select
57684 * @param {Boolean} keepExisting (optional) True to keep existing selections
57686 selectRecords : function(records, keepExisting){
57688 this.clearSelections();
57690 var ds = this.grid.dataSource;
57691 for(var i = 0, len = records.length; i < len; i++){
57692 this.selectRow(ds.indexOf(records[i]), true);
57697 * Gets the number of selected rows.
57700 getCount : function(){
57701 return this.selections.length;
57705 * Selects the first row in the grid.
57707 selectFirstRow : function(){
57712 * Select the last row.
57713 * @param {Boolean} keepExisting (optional) True to keep existing selections
57715 selectLastRow : function(keepExisting){
57716 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57720 * Selects the row immediately following the last selected row.
57721 * @param {Boolean} keepExisting (optional) True to keep existing selections
57723 selectNext : function(keepExisting){
57724 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57725 this.selectRow(this.last+1, keepExisting);
57726 this.grid.getView().focusRow(this.last);
57731 * Selects the row that precedes the last selected row.
57732 * @param {Boolean} keepExisting (optional) True to keep existing selections
57734 selectPrevious : function(keepExisting){
57736 this.selectRow(this.last-1, keepExisting);
57737 this.grid.getView().focusRow(this.last);
57742 * Returns the selected records
57743 * @return {Array} Array of selected records
57745 getSelections : function(){
57746 return [].concat(this.selections.items);
57750 * Returns the first selected record.
57753 getSelected : function(){
57754 return this.selections.itemAt(0);
57759 * Clears all selections.
57761 clearSelections : function(fast){
57766 var ds = this.grid.dataSource;
57767 var s = this.selections;
57768 s.each(function(r){
57769 this.deselectRow(ds.indexOfId(r.id));
57773 this.selections.clear();
57780 * Selects all rows.
57782 selectAll : function(){
57786 this.selections.clear();
57787 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57788 this.selectRow(i, true);
57793 * Returns True if there is a selection.
57794 * @return {Boolean}
57796 hasSelection : function(){
57797 return this.selections.length > 0;
57801 * Returns True if the specified row is selected.
57802 * @param {Number/Record} record The record or index of the record to check
57803 * @return {Boolean}
57805 isSelected : function(index){
57806 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57807 return (r && this.selections.key(r.id) ? true : false);
57811 * Returns True if the specified record id is selected.
57812 * @param {String} id The id of record to check
57813 * @return {Boolean}
57815 isIdSelected : function(id){
57816 return (this.selections.key(id) ? true : false);
57820 handleMouseDown : function(e, t){
57821 var view = this.grid.getView(), rowIndex;
57822 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57825 if(e.shiftKey && this.last !== false){
57826 var last = this.last;
57827 this.selectRange(last, rowIndex, e.ctrlKey);
57828 this.last = last; // reset the last
57829 view.focusRow(rowIndex);
57831 var isSelected = this.isSelected(rowIndex);
57832 if(e.button !== 0 && isSelected){
57833 view.focusRow(rowIndex);
57834 }else if(e.ctrlKey && isSelected){
57835 this.deselectRow(rowIndex);
57836 }else if(!isSelected){
57837 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57838 view.focusRow(rowIndex);
57841 this.fireEvent("afterselectionchange", this);
57844 handleDragableRowClick : function(grid, rowIndex, e)
57846 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57847 this.selectRow(rowIndex, false);
57848 grid.view.focusRow(rowIndex);
57849 this.fireEvent("afterselectionchange", this);
57854 * Selects multiple rows.
57855 * @param {Array} rows Array of the indexes of the row to select
57856 * @param {Boolean} keepExisting (optional) True to keep existing selections
57858 selectRows : function(rows, keepExisting){
57860 this.clearSelections();
57862 for(var i = 0, len = rows.length; i < len; i++){
57863 this.selectRow(rows[i], true);
57868 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57869 * @param {Number} startRow The index of the first row in the range
57870 * @param {Number} endRow The index of the last row in the range
57871 * @param {Boolean} keepExisting (optional) True to retain existing selections
57873 selectRange : function(startRow, endRow, keepExisting){
57878 this.clearSelections();
57880 if(startRow <= endRow){
57881 for(var i = startRow; i <= endRow; i++){
57882 this.selectRow(i, true);
57885 for(var i = startRow; i >= endRow; i--){
57886 this.selectRow(i, true);
57892 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57893 * @param {Number} startRow The index of the first row in the range
57894 * @param {Number} endRow The index of the last row in the range
57896 deselectRange : function(startRow, endRow, preventViewNotify){
57900 for(var i = startRow; i <= endRow; i++){
57901 this.deselectRow(i, preventViewNotify);
57907 * @param {Number} row The index of the row to select
57908 * @param {Boolean} keepExisting (optional) True to keep existing selections
57910 selectRow : function(index, keepExisting, preventViewNotify){
57911 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57914 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57915 if(!keepExisting || this.singleSelect){
57916 this.clearSelections();
57918 var r = this.grid.dataSource.getAt(index);
57919 this.selections.add(r);
57920 this.last = this.lastActive = index;
57921 if(!preventViewNotify){
57922 this.grid.getView().onRowSelect(index);
57924 this.fireEvent("rowselect", this, index, r);
57925 this.fireEvent("selectionchange", this);
57931 * @param {Number} row The index of the row to deselect
57933 deselectRow : function(index, preventViewNotify){
57937 if(this.last == index){
57940 if(this.lastActive == index){
57941 this.lastActive = false;
57943 var r = this.grid.dataSource.getAt(index);
57944 this.selections.remove(r);
57945 if(!preventViewNotify){
57946 this.grid.getView().onRowDeselect(index);
57948 this.fireEvent("rowdeselect", this, index);
57949 this.fireEvent("selectionchange", this);
57953 restoreLast : function(){
57955 this.last = this._last;
57960 acceptsNav : function(row, col, cm){
57961 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57965 onEditorKey : function(field, e){
57966 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57971 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57973 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57975 }else if(k == e.ENTER && !e.ctrlKey){
57979 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57981 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57983 }else if(k == e.ESC){
57987 g.startEditing(newCell[0], newCell[1]);
57992 * Ext JS Library 1.1.1
57993 * Copyright(c) 2006-2007, Ext JS, LLC.
57995 * Originally Released Under LGPL - original licence link has changed is not relivant.
57998 * <script type="text/javascript">
58001 * @class Roo.grid.CellSelectionModel
58002 * @extends Roo.grid.AbstractSelectionModel
58003 * This class provides the basic implementation for cell selection in a grid.
58005 * @param {Object} config The object containing the configuration of this model.
58006 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58008 Roo.grid.CellSelectionModel = function(config){
58009 Roo.apply(this, config);
58011 this.selection = null;
58015 * @event beforerowselect
58016 * Fires before a cell is selected.
58017 * @param {SelectionModel} this
58018 * @param {Number} rowIndex The selected row index
58019 * @param {Number} colIndex The selected cell index
58021 "beforecellselect" : true,
58023 * @event cellselect
58024 * Fires when a cell is selected.
58025 * @param {SelectionModel} this
58026 * @param {Number} rowIndex The selected row index
58027 * @param {Number} colIndex The selected cell index
58029 "cellselect" : true,
58031 * @event selectionchange
58032 * Fires when the active selection changes.
58033 * @param {SelectionModel} this
58034 * @param {Object} selection null for no selection or an object (o) with two properties
58036 <li>o.record: the record object for the row the selection is in</li>
58037 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58040 "selectionchange" : true,
58043 * Fires when the tab (or enter) was pressed on the last editable cell
58044 * You can use this to trigger add new row.
58045 * @param {SelectionModel} this
58049 * @event beforeeditnext
58050 * Fires before the next editable sell is made active
58051 * You can use this to skip to another cell or fire the tabend
58052 * if you set cell to false
58053 * @param {Object} eventdata object : { cell : [ row, col ] }
58055 "beforeeditnext" : true
58057 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58060 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58062 enter_is_tab: false,
58065 initEvents : function(){
58066 this.grid.on("mousedown", this.handleMouseDown, this);
58067 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58068 var view = this.grid.view;
58069 view.on("refresh", this.onViewChange, this);
58070 view.on("rowupdated", this.onRowUpdated, this);
58071 view.on("beforerowremoved", this.clearSelections, this);
58072 view.on("beforerowsinserted", this.clearSelections, this);
58073 if(this.grid.isEditor){
58074 this.grid.on("beforeedit", this.beforeEdit, this);
58079 beforeEdit : function(e){
58080 this.select(e.row, e.column, false, true, e.record);
58084 onRowUpdated : function(v, index, r){
58085 if(this.selection && this.selection.record == r){
58086 v.onCellSelect(index, this.selection.cell[1]);
58091 onViewChange : function(){
58092 this.clearSelections(true);
58096 * Returns the currently selected cell,.
58097 * @return {Array} The selected cell (row, column) or null if none selected.
58099 getSelectedCell : function(){
58100 return this.selection ? this.selection.cell : null;
58104 * Clears all selections.
58105 * @param {Boolean} true to prevent the gridview from being notified about the change.
58107 clearSelections : function(preventNotify){
58108 var s = this.selection;
58110 if(preventNotify !== true){
58111 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58113 this.selection = null;
58114 this.fireEvent("selectionchange", this, null);
58119 * Returns true if there is a selection.
58120 * @return {Boolean}
58122 hasSelection : function(){
58123 return this.selection ? true : false;
58127 handleMouseDown : function(e, t){
58128 var v = this.grid.getView();
58129 if(this.isLocked()){
58132 var row = v.findRowIndex(t);
58133 var cell = v.findCellIndex(t);
58134 if(row !== false && cell !== false){
58135 this.select(row, cell);
58141 * @param {Number} rowIndex
58142 * @param {Number} collIndex
58144 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58145 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58146 this.clearSelections();
58147 r = r || this.grid.dataSource.getAt(rowIndex);
58150 cell : [rowIndex, colIndex]
58152 if(!preventViewNotify){
58153 var v = this.grid.getView();
58154 v.onCellSelect(rowIndex, colIndex);
58155 if(preventFocus !== true){
58156 v.focusCell(rowIndex, colIndex);
58159 this.fireEvent("cellselect", this, rowIndex, colIndex);
58160 this.fireEvent("selectionchange", this, this.selection);
58165 isSelectable : function(rowIndex, colIndex, cm){
58166 return !cm.isHidden(colIndex);
58170 handleKeyDown : function(e){
58171 //Roo.log('Cell Sel Model handleKeyDown');
58172 if(!e.isNavKeyPress()){
58175 var g = this.grid, s = this.selection;
58178 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58180 this.select(cell[0], cell[1]);
58185 var walk = function(row, col, step){
58186 return g.walkCells(row, col, step, sm.isSelectable, sm);
58188 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58195 // handled by onEditorKey
58196 if (g.isEditor && g.editing) {
58200 newCell = walk(r, c-1, -1);
58202 newCell = walk(r, c+1, 1);
58207 newCell = walk(r+1, c, 1);
58211 newCell = walk(r-1, c, -1);
58215 newCell = walk(r, c+1, 1);
58219 newCell = walk(r, c-1, -1);
58224 if(g.isEditor && !g.editing){
58225 g.startEditing(r, c);
58234 this.select(newCell[0], newCell[1]);
58240 acceptsNav : function(row, col, cm){
58241 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58245 * @param {Number} field (not used) - as it's normally used as a listener
58246 * @param {Number} e - event - fake it by using
58248 * var e = Roo.EventObjectImpl.prototype;
58249 * e.keyCode = e.TAB
58253 onEditorKey : function(field, e){
58255 var k = e.getKey(),
58258 ed = g.activeEditor,
58260 ///Roo.log('onEditorKey' + k);
58263 if (this.enter_is_tab && k == e.ENTER) {
58269 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58271 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58277 } else if(k == e.ENTER && !e.ctrlKey){
58280 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58282 } else if(k == e.ESC){
58287 var ecall = { cell : newCell, forward : forward };
58288 this.fireEvent('beforeeditnext', ecall );
58289 newCell = ecall.cell;
58290 forward = ecall.forward;
58294 //Roo.log('next cell after edit');
58295 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58296 } else if (forward) {
58297 // tabbed past last
58298 this.fireEvent.defer(100, this, ['tabend',this]);
58303 * Ext JS Library 1.1.1
58304 * Copyright(c) 2006-2007, Ext JS, LLC.
58306 * Originally Released Under LGPL - original licence link has changed is not relivant.
58309 * <script type="text/javascript">
58313 * @class Roo.grid.EditorGrid
58314 * @extends Roo.grid.Grid
58315 * Class for creating and editable grid.
58316 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58317 * The container MUST have some type of size defined for the grid to fill. The container will be
58318 * automatically set to position relative if it isn't already.
58319 * @param {Object} dataSource The data model to bind to
58320 * @param {Object} colModel The column model with info about this grid's columns
58322 Roo.grid.EditorGrid = function(container, config){
58323 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58324 this.getGridEl().addClass("xedit-grid");
58326 if(!this.selModel){
58327 this.selModel = new Roo.grid.CellSelectionModel();
58330 this.activeEditor = null;
58334 * @event beforeedit
58335 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58336 * <ul style="padding:5px;padding-left:16px;">
58337 * <li>grid - This grid</li>
58338 * <li>record - The record being edited</li>
58339 * <li>field - The field name being edited</li>
58340 * <li>value - The value for the field being edited.</li>
58341 * <li>row - The grid row index</li>
58342 * <li>column - The grid column index</li>
58343 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58345 * @param {Object} e An edit event (see above for description)
58347 "beforeedit" : true,
58350 * Fires after a cell is edited. <br />
58351 * <ul style="padding:5px;padding-left:16px;">
58352 * <li>grid - This grid</li>
58353 * <li>record - The record being edited</li>
58354 * <li>field - The field name being edited</li>
58355 * <li>value - The value being set</li>
58356 * <li>originalValue - The original value for the field, before the edit.</li>
58357 * <li>row - The grid row index</li>
58358 * <li>column - The grid column index</li>
58360 * @param {Object} e An edit event (see above for description)
58362 "afteredit" : true,
58364 * @event validateedit
58365 * Fires after a cell is edited, but before the value is set in the record.
58366 * You can use this to modify the value being set in the field, Return false
58367 * to cancel the change. The edit event object has the following properties <br />
58368 * <ul style="padding:5px;padding-left:16px;">
58369 * <li>editor - This editor</li>
58370 * <li>grid - This grid</li>
58371 * <li>record - The record being edited</li>
58372 * <li>field - The field name being edited</li>
58373 * <li>value - The value being set</li>
58374 * <li>originalValue - The original value for the field, before the edit.</li>
58375 * <li>row - The grid row index</li>
58376 * <li>column - The grid column index</li>
58377 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58379 * @param {Object} e An edit event (see above for description)
58381 "validateedit" : true
58383 this.on("bodyscroll", this.stopEditing, this);
58384 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58387 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58389 * @cfg {Number} clicksToEdit
58390 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58397 trackMouseOver: false, // causes very odd FF errors
58399 onCellDblClick : function(g, row, col){
58400 this.startEditing(row, col);
58403 onEditComplete : function(ed, value, startValue){
58404 this.editing = false;
58405 this.activeEditor = null;
58406 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58408 var field = this.colModel.getDataIndex(ed.col);
58413 originalValue: startValue,
58420 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58423 if(String(value) !== String(startValue)){
58425 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58426 r.set(field, e.value);
58427 // if we are dealing with a combo box..
58428 // then we also set the 'name' colum to be the displayField
58429 if (ed.field.displayField && ed.field.name) {
58430 r.set(ed.field.name, ed.field.el.dom.value);
58433 delete e.cancel; //?? why!!!
58434 this.fireEvent("afteredit", e);
58437 this.fireEvent("afteredit", e); // always fire it!
58439 this.view.focusCell(ed.row, ed.col);
58443 * Starts editing the specified for the specified row/column
58444 * @param {Number} rowIndex
58445 * @param {Number} colIndex
58447 startEditing : function(row, col){
58448 this.stopEditing();
58449 if(this.colModel.isCellEditable(col, row)){
58450 this.view.ensureVisible(row, col, true);
58452 var r = this.dataSource.getAt(row);
58453 var field = this.colModel.getDataIndex(col);
58454 var cell = Roo.get(this.view.getCell(row,col));
58459 value: r.data[field],
58464 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58465 this.editing = true;
58466 var ed = this.colModel.getCellEditor(col, row);
58472 ed.render(ed.parentEl || document.body);
58478 (function(){ // complex but required for focus issues in safari, ie and opera
58482 ed.on("complete", this.onEditComplete, this, {single: true});
58483 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58484 this.activeEditor = ed;
58485 var v = r.data[field];
58486 ed.startEdit(this.view.getCell(row, col), v);
58487 // combo's with 'displayField and name set
58488 if (ed.field.displayField && ed.field.name) {
58489 ed.field.el.dom.value = r.data[ed.field.name];
58493 }).defer(50, this);
58499 * Stops any active editing
58501 stopEditing : function(){
58502 if(this.activeEditor){
58503 this.activeEditor.completeEdit();
58505 this.activeEditor = null;
58509 * Called to get grid's drag proxy text, by default returns this.ddText.
58512 getDragDropText : function(){
58513 var count = this.selModel.getSelectedCell() ? 1 : 0;
58514 return String.format(this.ddText, count, count == 1 ? '' : 's');
58519 * Ext JS Library 1.1.1
58520 * Copyright(c) 2006-2007, Ext JS, LLC.
58522 * Originally Released Under LGPL - original licence link has changed is not relivant.
58525 * <script type="text/javascript">
58528 // private - not really -- you end up using it !
58529 // This is a support class used internally by the Grid components
58532 * @class Roo.grid.GridEditor
58533 * @extends Roo.Editor
58534 * Class for creating and editable grid elements.
58535 * @param {Object} config any settings (must include field)
58537 Roo.grid.GridEditor = function(field, config){
58538 if (!config && field.field) {
58540 field = Roo.factory(config.field, Roo.form);
58542 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58543 field.monitorTab = false;
58546 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58549 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58552 alignment: "tl-tl",
58555 cls: "x-small-editor x-grid-editor",
58560 * Ext JS Library 1.1.1
58561 * Copyright(c) 2006-2007, Ext JS, LLC.
58563 * Originally Released Under LGPL - original licence link has changed is not relivant.
58566 * <script type="text/javascript">
58571 Roo.grid.PropertyRecord = Roo.data.Record.create([
58572 {name:'name',type:'string'}, 'value'
58576 Roo.grid.PropertyStore = function(grid, source){
58578 this.store = new Roo.data.Store({
58579 recordType : Roo.grid.PropertyRecord
58581 this.store.on('update', this.onUpdate, this);
58583 this.setSource(source);
58585 Roo.grid.PropertyStore.superclass.constructor.call(this);
58590 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58591 setSource : function(o){
58593 this.store.removeAll();
58596 if(this.isEditableValue(o[k])){
58597 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58600 this.store.loadRecords({records: data}, {}, true);
58603 onUpdate : function(ds, record, type){
58604 if(type == Roo.data.Record.EDIT){
58605 var v = record.data['value'];
58606 var oldValue = record.modified['value'];
58607 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58608 this.source[record.id] = v;
58610 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58617 getProperty : function(row){
58618 return this.store.getAt(row);
58621 isEditableValue: function(val){
58622 if(val && val instanceof Date){
58624 }else if(typeof val == 'object' || typeof val == 'function'){
58630 setValue : function(prop, value){
58631 this.source[prop] = value;
58632 this.store.getById(prop).set('value', value);
58635 getSource : function(){
58636 return this.source;
58640 Roo.grid.PropertyColumnModel = function(grid, store){
58643 g.PropertyColumnModel.superclass.constructor.call(this, [
58644 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58645 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58647 this.store = store;
58648 this.bselect = Roo.DomHelper.append(document.body, {
58649 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58650 {tag: 'option', value: 'true', html: 'true'},
58651 {tag: 'option', value: 'false', html: 'false'}
58654 Roo.id(this.bselect);
58657 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58658 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58659 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58660 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58661 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58663 this.renderCellDelegate = this.renderCell.createDelegate(this);
58664 this.renderPropDelegate = this.renderProp.createDelegate(this);
58667 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58671 valueText : 'Value',
58673 dateFormat : 'm/j/Y',
58676 renderDate : function(dateVal){
58677 return dateVal.dateFormat(this.dateFormat);
58680 renderBool : function(bVal){
58681 return bVal ? 'true' : 'false';
58684 isCellEditable : function(colIndex, rowIndex){
58685 return colIndex == 1;
58688 getRenderer : function(col){
58690 this.renderCellDelegate : this.renderPropDelegate;
58693 renderProp : function(v){
58694 return this.getPropertyName(v);
58697 renderCell : function(val){
58699 if(val instanceof Date){
58700 rv = this.renderDate(val);
58701 }else if(typeof val == 'boolean'){
58702 rv = this.renderBool(val);
58704 return Roo.util.Format.htmlEncode(rv);
58707 getPropertyName : function(name){
58708 var pn = this.grid.propertyNames;
58709 return pn && pn[name] ? pn[name] : name;
58712 getCellEditor : function(colIndex, rowIndex){
58713 var p = this.store.getProperty(rowIndex);
58714 var n = p.data['name'], val = p.data['value'];
58716 if(typeof(this.grid.customEditors[n]) == 'string'){
58717 return this.editors[this.grid.customEditors[n]];
58719 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58720 return this.grid.customEditors[n];
58722 if(val instanceof Date){
58723 return this.editors['date'];
58724 }else if(typeof val == 'number'){
58725 return this.editors['number'];
58726 }else if(typeof val == 'boolean'){
58727 return this.editors['boolean'];
58729 return this.editors['string'];
58735 * @class Roo.grid.PropertyGrid
58736 * @extends Roo.grid.EditorGrid
58737 * This class represents the interface of a component based property grid control.
58738 * <br><br>Usage:<pre><code>
58739 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58747 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58748 * The container MUST have some type of size defined for the grid to fill. The container will be
58749 * automatically set to position relative if it isn't already.
58750 * @param {Object} config A config object that sets properties on this grid.
58752 Roo.grid.PropertyGrid = function(container, config){
58753 config = config || {};
58754 var store = new Roo.grid.PropertyStore(this);
58755 this.store = store;
58756 var cm = new Roo.grid.PropertyColumnModel(this, store);
58757 store.store.sort('name', 'ASC');
58758 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58761 enableColLock:false,
58762 enableColumnMove:false,
58764 trackMouseOver: false,
58767 this.getGridEl().addClass('x-props-grid');
58768 this.lastEditRow = null;
58769 this.on('columnresize', this.onColumnResize, this);
58772 * @event beforepropertychange
58773 * Fires before a property changes (return false to stop?)
58774 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58775 * @param {String} id Record Id
58776 * @param {String} newval New Value
58777 * @param {String} oldval Old Value
58779 "beforepropertychange": true,
58781 * @event propertychange
58782 * Fires after a property changes
58783 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58784 * @param {String} id Record Id
58785 * @param {String} newval New Value
58786 * @param {String} oldval Old Value
58788 "propertychange": true
58790 this.customEditors = this.customEditors || {};
58792 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58795 * @cfg {Object} customEditors map of colnames=> custom editors.
58796 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58797 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58798 * false disables editing of the field.
58802 * @cfg {Object} propertyNames map of property Names to their displayed value
58805 render : function(){
58806 Roo.grid.PropertyGrid.superclass.render.call(this);
58807 this.autoSize.defer(100, this);
58810 autoSize : function(){
58811 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58813 this.view.fitColumns();
58817 onColumnResize : function(){
58818 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58822 * Sets the data for the Grid
58823 * accepts a Key => Value object of all the elements avaiable.
58824 * @param {Object} data to appear in grid.
58826 setSource : function(source){
58827 this.store.setSource(source);
58831 * Gets all the data from the grid.
58832 * @return {Object} data data stored in grid
58834 getSource : function(){
58835 return this.store.getSource();
58844 * @class Roo.grid.Calendar
58845 * @extends Roo.util.Grid
58846 * This class extends the Grid to provide a calendar widget
58847 * <br><br>Usage:<pre><code>
58848 var grid = new Roo.grid.Calendar("my-container-id", {
58851 selModel: mySelectionModel,
58852 autoSizeColumns: true,
58853 monitorWindowResize: false,
58854 trackMouseOver: true
58855 eventstore : real data store..
58861 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58862 * The container MUST have some type of size defined for the grid to fill. The container will be
58863 * automatically set to position relative if it isn't already.
58864 * @param {Object} config A config object that sets properties on this grid.
58866 Roo.grid.Calendar = function(container, config){
58867 // initialize the container
58868 this.container = Roo.get(container);
58869 this.container.update("");
58870 this.container.setStyle("overflow", "hidden");
58871 this.container.addClass('x-grid-container');
58873 this.id = this.container.id;
58875 Roo.apply(this, config);
58876 // check and correct shorthanded configs
58880 for (var r = 0;r < 6;r++) {
58883 for (var c =0;c < 7;c++) {
58887 if (this.eventStore) {
58888 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58889 this.eventStore.on('load',this.onLoad, this);
58890 this.eventStore.on('beforeload',this.clearEvents, this);
58894 this.dataSource = new Roo.data.Store({
58895 proxy: new Roo.data.MemoryProxy(rows),
58896 reader: new Roo.data.ArrayReader({}, [
58897 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58900 this.dataSource.load();
58901 this.ds = this.dataSource;
58902 this.ds.xmodule = this.xmodule || false;
58905 var cellRender = function(v,x,r)
58907 return String.format(
58908 '<div class="fc-day fc-widget-content"><div>' +
58909 '<div class="fc-event-container"></div>' +
58910 '<div class="fc-day-number">{0}</div>'+
58912 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58913 '</div></div>', v);
58918 this.colModel = new Roo.grid.ColumnModel( [
58920 xtype: 'ColumnModel',
58922 dataIndex : 'weekday0',
58924 renderer : cellRender
58927 xtype: 'ColumnModel',
58929 dataIndex : 'weekday1',
58931 renderer : cellRender
58934 xtype: 'ColumnModel',
58936 dataIndex : 'weekday2',
58937 header : 'Tuesday',
58938 renderer : cellRender
58941 xtype: 'ColumnModel',
58943 dataIndex : 'weekday3',
58944 header : 'Wednesday',
58945 renderer : cellRender
58948 xtype: 'ColumnModel',
58950 dataIndex : 'weekday4',
58951 header : 'Thursday',
58952 renderer : cellRender
58955 xtype: 'ColumnModel',
58957 dataIndex : 'weekday5',
58959 renderer : cellRender
58962 xtype: 'ColumnModel',
58964 dataIndex : 'weekday6',
58965 header : 'Saturday',
58966 renderer : cellRender
58969 this.cm = this.colModel;
58970 this.cm.xmodule = this.xmodule || false;
58974 //this.selModel = new Roo.grid.CellSelectionModel();
58975 //this.sm = this.selModel;
58976 //this.selModel.init(this);
58980 this.container.setWidth(this.width);
58984 this.container.setHeight(this.height);
58991 * The raw click event for the entire grid.
58992 * @param {Roo.EventObject} e
58997 * The raw dblclick event for the entire grid.
58998 * @param {Roo.EventObject} e
59002 * @event contextmenu
59003 * The raw contextmenu event for the entire grid.
59004 * @param {Roo.EventObject} e
59006 "contextmenu" : true,
59009 * The raw mousedown event for the entire grid.
59010 * @param {Roo.EventObject} e
59012 "mousedown" : true,
59015 * The raw mouseup event for the entire grid.
59016 * @param {Roo.EventObject} e
59021 * The raw mouseover event for the entire grid.
59022 * @param {Roo.EventObject} e
59024 "mouseover" : true,
59027 * The raw mouseout event for the entire grid.
59028 * @param {Roo.EventObject} e
59033 * The raw keypress event for the entire grid.
59034 * @param {Roo.EventObject} e
59039 * The raw keydown event for the entire grid.
59040 * @param {Roo.EventObject} e
59048 * Fires when a cell is clicked
59049 * @param {Grid} this
59050 * @param {Number} rowIndex
59051 * @param {Number} columnIndex
59052 * @param {Roo.EventObject} e
59054 "cellclick" : true,
59056 * @event celldblclick
59057 * Fires when a cell is double clicked
59058 * @param {Grid} this
59059 * @param {Number} rowIndex
59060 * @param {Number} columnIndex
59061 * @param {Roo.EventObject} e
59063 "celldblclick" : true,
59066 * Fires when a row is clicked
59067 * @param {Grid} this
59068 * @param {Number} rowIndex
59069 * @param {Roo.EventObject} e
59073 * @event rowdblclick
59074 * Fires when a row is double clicked
59075 * @param {Grid} this
59076 * @param {Number} rowIndex
59077 * @param {Roo.EventObject} e
59079 "rowdblclick" : true,
59081 * @event headerclick
59082 * Fires when a header is clicked
59083 * @param {Grid} this
59084 * @param {Number} columnIndex
59085 * @param {Roo.EventObject} e
59087 "headerclick" : true,
59089 * @event headerdblclick
59090 * Fires when a header cell is double clicked
59091 * @param {Grid} this
59092 * @param {Number} columnIndex
59093 * @param {Roo.EventObject} e
59095 "headerdblclick" : true,
59097 * @event rowcontextmenu
59098 * Fires when a row is right clicked
59099 * @param {Grid} this
59100 * @param {Number} rowIndex
59101 * @param {Roo.EventObject} e
59103 "rowcontextmenu" : true,
59105 * @event cellcontextmenu
59106 * Fires when a cell is right clicked
59107 * @param {Grid} this
59108 * @param {Number} rowIndex
59109 * @param {Number} cellIndex
59110 * @param {Roo.EventObject} e
59112 "cellcontextmenu" : true,
59114 * @event headercontextmenu
59115 * Fires when a header is right clicked
59116 * @param {Grid} this
59117 * @param {Number} columnIndex
59118 * @param {Roo.EventObject} e
59120 "headercontextmenu" : true,
59122 * @event bodyscroll
59123 * Fires when the body element is scrolled
59124 * @param {Number} scrollLeft
59125 * @param {Number} scrollTop
59127 "bodyscroll" : true,
59129 * @event columnresize
59130 * Fires when the user resizes a column
59131 * @param {Number} columnIndex
59132 * @param {Number} newSize
59134 "columnresize" : true,
59136 * @event columnmove
59137 * Fires when the user moves a column
59138 * @param {Number} oldIndex
59139 * @param {Number} newIndex
59141 "columnmove" : true,
59144 * Fires when row(s) start being dragged
59145 * @param {Grid} this
59146 * @param {Roo.GridDD} dd The drag drop object
59147 * @param {event} e The raw browser event
59149 "startdrag" : true,
59152 * Fires when a drag operation is complete
59153 * @param {Grid} this
59154 * @param {Roo.GridDD} dd The drag drop object
59155 * @param {event} e The raw browser event
59160 * Fires when dragged row(s) are dropped on a valid DD target
59161 * @param {Grid} this
59162 * @param {Roo.GridDD} dd The drag drop object
59163 * @param {String} targetId The target drag drop object
59164 * @param {event} e The raw browser event
59169 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59170 * @param {Grid} this
59171 * @param {Roo.GridDD} dd The drag drop object
59172 * @param {String} targetId The target drag drop object
59173 * @param {event} e The raw browser event
59178 * Fires when the dragged row(s) first cross another DD target while being dragged
59179 * @param {Grid} this
59180 * @param {Roo.GridDD} dd The drag drop object
59181 * @param {String} targetId The target drag drop object
59182 * @param {event} e The raw browser event
59184 "dragenter" : true,
59187 * Fires when the dragged row(s) leave another DD target while being dragged
59188 * @param {Grid} this
59189 * @param {Roo.GridDD} dd The drag drop object
59190 * @param {String} targetId The target drag drop object
59191 * @param {event} e The raw browser event
59196 * Fires when a row is rendered, so you can change add a style to it.
59197 * @param {GridView} gridview The grid view
59198 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59204 * Fires when the grid is rendered
59205 * @param {Grid} grid
59210 * Fires when a date is selected
59211 * @param {DatePicker} this
59212 * @param {Date} date The selected date
59216 * @event monthchange
59217 * Fires when the displayed month changes
59218 * @param {DatePicker} this
59219 * @param {Date} date The selected month
59221 'monthchange': true,
59223 * @event evententer
59224 * Fires when mouse over an event
59225 * @param {Calendar} this
59226 * @param {event} Event
59228 'evententer': true,
59230 * @event eventleave
59231 * Fires when the mouse leaves an
59232 * @param {Calendar} this
59235 'eventleave': true,
59237 * @event eventclick
59238 * Fires when the mouse click an
59239 * @param {Calendar} this
59242 'eventclick': true,
59244 * @event eventrender
59245 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59246 * @param {Calendar} this
59247 * @param {data} data to be modified
59249 'eventrender': true
59253 Roo.grid.Grid.superclass.constructor.call(this);
59254 this.on('render', function() {
59255 this.view.el.addClass('x-grid-cal');
59257 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59261 if (!Roo.grid.Calendar.style) {
59262 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59265 '.x-grid-cal .x-grid-col' : {
59266 height: 'auto !important',
59267 'vertical-align': 'top'
59269 '.x-grid-cal .fc-event-hori' : {
59280 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59282 * @cfg {Store} eventStore The store that loads events.
59287 activeDate : false,
59290 monitorWindowResize : false,
59293 resizeColumns : function() {
59294 var col = (this.view.el.getWidth() / 7) - 3;
59295 // loop through cols, and setWidth
59296 for(var i =0 ; i < 7 ; i++){
59297 this.cm.setColumnWidth(i, col);
59300 setDate :function(date) {
59302 Roo.log('setDate?');
59304 this.resizeColumns();
59305 var vd = this.activeDate;
59306 this.activeDate = date;
59307 // if(vd && this.el){
59308 // var t = date.getTime();
59309 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59310 // Roo.log('using add remove');
59312 // this.fireEvent('monthchange', this, date);
59314 // this.cells.removeClass("fc-state-highlight");
59315 // this.cells.each(function(c){
59316 // if(c.dateValue == t){
59317 // c.addClass("fc-state-highlight");
59318 // setTimeout(function(){
59319 // try{c.dom.firstChild.focus();}catch(e){}
59329 var days = date.getDaysInMonth();
59331 var firstOfMonth = date.getFirstDateOfMonth();
59332 var startingPos = firstOfMonth.getDay()-this.startDay;
59334 if(startingPos < this.startDay){
59338 var pm = date.add(Date.MONTH, -1);
59339 var prevStart = pm.getDaysInMonth()-startingPos;
59343 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59345 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59346 //this.cells.addClassOnOver('fc-state-hover');
59348 var cells = this.cells.elements;
59349 var textEls = this.textNodes;
59351 //Roo.each(cells, function(cell){
59352 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59355 days += startingPos;
59357 // convert everything to numbers so it's fast
59358 var day = 86400000;
59359 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59362 //Roo.log(prevStart);
59364 var today = new Date().clearTime().getTime();
59365 var sel = date.clearTime().getTime();
59366 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59367 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59368 var ddMatch = this.disabledDatesRE;
59369 var ddText = this.disabledDatesText;
59370 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59371 var ddaysText = this.disabledDaysText;
59372 var format = this.format;
59374 var setCellClass = function(cal, cell){
59376 //Roo.log('set Cell Class');
59378 var t = d.getTime();
59383 cell.dateValue = t;
59385 cell.className += " fc-today";
59386 cell.className += " fc-state-highlight";
59387 cell.title = cal.todayText;
59390 // disable highlight in other month..
59391 cell.className += " fc-state-highlight";
59396 //cell.className = " fc-state-disabled";
59397 cell.title = cal.minText;
59401 //cell.className = " fc-state-disabled";
59402 cell.title = cal.maxText;
59406 if(ddays.indexOf(d.getDay()) != -1){
59407 // cell.title = ddaysText;
59408 // cell.className = " fc-state-disabled";
59411 if(ddMatch && format){
59412 var fvalue = d.dateFormat(format);
59413 if(ddMatch.test(fvalue)){
59414 cell.title = ddText.replace("%0", fvalue);
59415 cell.className = " fc-state-disabled";
59419 if (!cell.initialClassName) {
59420 cell.initialClassName = cell.dom.className;
59423 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59428 for(; i < startingPos; i++) {
59429 cells[i].dayName = (++prevStart);
59430 Roo.log(textEls[i]);
59431 d.setDate(d.getDate()+1);
59433 //cells[i].className = "fc-past fc-other-month";
59434 setCellClass(this, cells[i]);
59439 for(; i < days; i++){
59440 intDay = i - startingPos + 1;
59441 cells[i].dayName = (intDay);
59442 d.setDate(d.getDate()+1);
59444 cells[i].className = ''; // "x-date-active";
59445 setCellClass(this, cells[i]);
59449 for(; i < 42; i++) {
59450 //textEls[i].innerHTML = (++extraDays);
59452 d.setDate(d.getDate()+1);
59453 cells[i].dayName = (++extraDays);
59454 cells[i].className = "fc-future fc-other-month";
59455 setCellClass(this, cells[i]);
59458 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59460 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59462 // this will cause all the cells to mis
59465 for (var r = 0;r < 6;r++) {
59466 for (var c =0;c < 7;c++) {
59467 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59471 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59472 for(i=0;i<cells.length;i++) {
59474 this.cells.elements[i].dayName = cells[i].dayName ;
59475 this.cells.elements[i].className = cells[i].className;
59476 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59477 this.cells.elements[i].title = cells[i].title ;
59478 this.cells.elements[i].dateValue = cells[i].dateValue ;
59484 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59485 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59487 ////if(totalRows != 6){
59488 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59489 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59492 this.fireEvent('monthchange', this, date);
59497 * Returns the grid's SelectionModel.
59498 * @return {SelectionModel}
59500 getSelectionModel : function(){
59501 if(!this.selModel){
59502 this.selModel = new Roo.grid.CellSelectionModel();
59504 return this.selModel;
59508 this.eventStore.load()
59514 findCell : function(dt) {
59515 dt = dt.clearTime().getTime();
59517 this.cells.each(function(c){
59518 //Roo.log("check " +c.dateValue + '?=' + dt);
59519 if(c.dateValue == dt){
59529 findCells : function(rec) {
59530 var s = rec.data.start_dt.clone().clearTime().getTime();
59532 var e= rec.data.end_dt.clone().clearTime().getTime();
59535 this.cells.each(function(c){
59536 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59538 if(c.dateValue > e){
59541 if(c.dateValue < s){
59550 findBestRow: function(cells)
59554 for (var i =0 ; i < cells.length;i++) {
59555 ret = Math.max(cells[i].rows || 0,ret);
59562 addItem : function(rec)
59564 // look for vertical location slot in
59565 var cells = this.findCells(rec);
59567 rec.row = this.findBestRow(cells);
59569 // work out the location.
59573 for(var i =0; i < cells.length; i++) {
59581 if (crow.start.getY() == cells[i].getY()) {
59583 crow.end = cells[i];
59599 for (var i = 0; i < cells.length;i++) {
59600 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59607 clearEvents: function() {
59609 if (!this.eventStore.getCount()) {
59612 // reset number of rows in cells.
59613 Roo.each(this.cells.elements, function(c){
59617 this.eventStore.each(function(e) {
59618 this.clearEvent(e);
59623 clearEvent : function(ev)
59626 Roo.each(ev.els, function(el) {
59627 el.un('mouseenter' ,this.onEventEnter, this);
59628 el.un('mouseleave' ,this.onEventLeave, this);
59636 renderEvent : function(ev,ctr) {
59638 ctr = this.view.el.select('.fc-event-container',true).first();
59642 this.clearEvent(ev);
59648 var cells = ev.cells;
59649 var rows = ev.rows;
59650 this.fireEvent('eventrender', this, ev);
59652 for(var i =0; i < rows.length; i++) {
59656 cls += ' fc-event-start';
59658 if ((i+1) == rows.length) {
59659 cls += ' fc-event-end';
59662 //Roo.log(ev.data);
59663 // how many rows should it span..
59664 var cg = this.eventTmpl.append(ctr,Roo.apply({
59667 }, ev.data) , true);
59670 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59671 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59672 cg.on('click', this.onEventClick, this, ev);
59676 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59677 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59680 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59681 cg.setWidth(ebox.right - sbox.x -2);
59685 renderEvents: function()
59687 // first make sure there is enough space..
59689 if (!this.eventTmpl) {
59690 this.eventTmpl = new Roo.Template(
59691 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59692 '<div class="fc-event-inner">' +
59693 '<span class="fc-event-time">{time}</span>' +
59694 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59696 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59704 this.cells.each(function(c) {
59705 //Roo.log(c.select('.fc-day-content div',true).first());
59706 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59709 var ctr = this.view.el.select('.fc-event-container',true).first();
59712 this.eventStore.each(function(ev){
59714 this.renderEvent(ev);
59718 this.view.layout();
59722 onEventEnter: function (e, el,event,d) {
59723 this.fireEvent('evententer', this, el, event);
59726 onEventLeave: function (e, el,event,d) {
59727 this.fireEvent('eventleave', this, el, event);
59730 onEventClick: function (e, el,event,d) {
59731 this.fireEvent('eventclick', this, el, event);
59734 onMonthChange: function () {
59738 onLoad: function () {
59740 //Roo.log('calendar onload');
59742 if(this.eventStore.getCount() > 0){
59746 this.eventStore.each(function(d){
59751 if (typeof(add.end_dt) == 'undefined') {
59752 Roo.log("Missing End time in calendar data: ");
59756 if (typeof(add.start_dt) == 'undefined') {
59757 Roo.log("Missing Start time in calendar data: ");
59761 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59762 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59763 add.id = add.id || d.id;
59764 add.title = add.title || '??';
59772 this.renderEvents();
59782 render : function ()
59786 if (!this.view.el.hasClass('course-timesheet')) {
59787 this.view.el.addClass('course-timesheet');
59789 if (this.tsStyle) {
59794 Roo.log(_this.grid.view.el.getWidth());
59797 this.tsStyle = Roo.util.CSS.createStyleSheet({
59798 '.course-timesheet .x-grid-row' : {
59801 '.x-grid-row td' : {
59802 'vertical-align' : 0
59804 '.course-edit-link' : {
59806 'text-overflow' : 'ellipsis',
59807 'overflow' : 'hidden',
59808 'white-space' : 'nowrap',
59809 'cursor' : 'pointer'
59814 '.de-act-sup-link' : {
59815 'color' : 'purple',
59816 'text-decoration' : 'line-through'
59820 'text-decoration' : 'line-through'
59822 '.course-timesheet .course-highlight' : {
59823 'border-top-style': 'dashed !important',
59824 'border-bottom-bottom': 'dashed !important'
59826 '.course-timesheet .course-item' : {
59827 'font-family' : 'tahoma, arial, helvetica',
59828 'font-size' : '11px',
59829 'overflow' : 'hidden',
59830 'padding-left' : '10px',
59831 'padding-right' : '10px',
59832 'padding-top' : '10px'
59840 monitorWindowResize : false,
59841 cellrenderer : function(v,x,r)
59846 xtype: 'CellSelectionModel',
59853 beforeload : function (_self, options)
59855 options.params = options.params || {};
59856 options.params._month = _this.monthField.getValue();
59857 options.params.limit = 9999;
59858 options.params['sort'] = 'when_dt';
59859 options.params['dir'] = 'ASC';
59860 this.proxy.loadResponse = this.loadResponse;
59862 //this.addColumns();
59864 load : function (_self, records, options)
59866 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59867 // if you click on the translation.. you can edit it...
59868 var el = Roo.get(this);
59869 var id = el.dom.getAttribute('data-id');
59870 var d = el.dom.getAttribute('data-date');
59871 var t = el.dom.getAttribute('data-time');
59872 //var id = this.child('span').dom.textContent;
59875 Pman.Dialog.CourseCalendar.show({
59879 productitem_active : id ? 1 : 0
59881 _this.grid.ds.load({});
59886 _this.panel.fireEvent('resize', [ '', '' ]);
59889 loadResponse : function(o, success, response){
59890 // this is overridden on before load..
59892 Roo.log("our code?");
59893 //Roo.log(success);
59894 //Roo.log(response)
59895 delete this.activeRequest;
59897 this.fireEvent("loadexception", this, o, response);
59898 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59903 result = o.reader.read(response);
59905 Roo.log("load exception?");
59906 this.fireEvent("loadexception", this, o, response, e);
59907 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59910 Roo.log("ready...");
59911 // loop through result.records;
59912 // and set this.tdate[date] = [] << array of records..
59914 Roo.each(result.records, function(r){
59916 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59917 _this.tdata[r.data.when_dt.format('j')] = [];
59919 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59922 //Roo.log(_this.tdata);
59924 result.records = [];
59925 result.totalRecords = 6;
59927 // let's generate some duumy records for the rows.
59928 //var st = _this.dateField.getValue();
59930 // work out monday..
59931 //st = st.add(Date.DAY, -1 * st.format('w'));
59933 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59935 var firstOfMonth = date.getFirstDayOfMonth();
59936 var days = date.getDaysInMonth();
59938 var firstAdded = false;
59939 for (var i = 0; i < result.totalRecords ; i++) {
59940 //var d= st.add(Date.DAY, i);
59943 for(var w = 0 ; w < 7 ; w++){
59944 if(!firstAdded && firstOfMonth != w){
59951 var dd = (d > 0 && d < 10) ? "0"+d : d;
59952 row['weekday'+w] = String.format(
59953 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59954 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59956 date.format('Y-m-')+dd
59959 if(typeof(_this.tdata[d]) != 'undefined'){
59960 Roo.each(_this.tdata[d], function(r){
59964 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59965 if(r.parent_id*1>0){
59966 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59969 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59970 deactive = 'de-act-link';
59973 row['weekday'+w] += String.format(
59974 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59976 r.product_id_name, //1
59977 r.when_dt.format('h:ia'), //2
59987 // only do this if something added..
59989 result.records.push(_this.grid.dataSource.reader.newRow(row));
59993 // push it twice. (second one with an hour..
59997 this.fireEvent("load", this, o, o.request.arg);
59998 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60000 sortInfo : {field: 'when_dt', direction : 'ASC' },
60002 xtype: 'HttpProxy',
60005 url : baseURL + '/Roo/Shop_course.php'
60008 xtype: 'JsonReader',
60025 'name': 'parent_id',
60029 'name': 'product_id',
60033 'name': 'productitem_id',
60051 click : function (_self, e)
60053 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60054 sd.setMonth(sd.getMonth()-1);
60055 _this.monthField.setValue(sd.format('Y-m-d'));
60056 _this.grid.ds.load({});
60062 xtype: 'Separator',
60066 xtype: 'MonthField',
60069 render : function (_self)
60071 _this.monthField = _self;
60072 // _this.monthField.set today
60074 select : function (combo, date)
60076 _this.grid.ds.load({});
60079 value : (function() { return new Date(); })()
60082 xtype: 'Separator',
60088 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60098 click : function (_self, e)
60100 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60101 sd.setMonth(sd.getMonth()+1);
60102 _this.monthField.setValue(sd.format('Y-m-d'));
60103 _this.grid.ds.load({});
60116 * Ext JS Library 1.1.1
60117 * Copyright(c) 2006-2007, Ext JS, LLC.
60119 * Originally Released Under LGPL - original licence link has changed is not relivant.
60122 * <script type="text/javascript">
60126 * @class Roo.LoadMask
60127 * A simple utility class for generically masking elements while loading data. If the element being masked has
60128 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60129 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60130 * element's UpdateManager load indicator and will be destroyed after the initial load.
60132 * Create a new LoadMask
60133 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60134 * @param {Object} config The config object
60136 Roo.LoadMask = function(el, config){
60137 this.el = Roo.get(el);
60138 Roo.apply(this, config);
60140 this.store.on('beforeload', this.onBeforeLoad, this);
60141 this.store.on('load', this.onLoad, this);
60142 this.store.on('loadexception', this.onLoadException, this);
60143 this.removeMask = false;
60145 var um = this.el.getUpdateManager();
60146 um.showLoadIndicator = false; // disable the default indicator
60147 um.on('beforeupdate', this.onBeforeLoad, this);
60148 um.on('update', this.onLoad, this);
60149 um.on('failure', this.onLoad, this);
60150 this.removeMask = true;
60154 Roo.LoadMask.prototype = {
60156 * @cfg {Boolean} removeMask
60157 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60158 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60161 * @cfg {String} msg
60162 * The text to display in a centered loading message box (defaults to 'Loading...')
60164 msg : 'Loading...',
60166 * @cfg {String} msgCls
60167 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60169 msgCls : 'x-mask-loading',
60172 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60178 * Disables the mask to prevent it from being displayed
60180 disable : function(){
60181 this.disabled = true;
60185 * Enables the mask so that it can be displayed
60187 enable : function(){
60188 this.disabled = false;
60191 onLoadException : function()
60193 Roo.log(arguments);
60195 if (typeof(arguments[3]) != 'undefined') {
60196 Roo.MessageBox.alert("Error loading",arguments[3]);
60200 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60201 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60208 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60211 onLoad : function()
60213 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60217 onBeforeLoad : function(){
60218 if(!this.disabled){
60219 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60224 destroy : function(){
60226 this.store.un('beforeload', this.onBeforeLoad, this);
60227 this.store.un('load', this.onLoad, this);
60228 this.store.un('loadexception', this.onLoadException, this);
60230 var um = this.el.getUpdateManager();
60231 um.un('beforeupdate', this.onBeforeLoad, this);
60232 um.un('update', this.onLoad, this);
60233 um.un('failure', this.onLoad, this);
60238 * Ext JS Library 1.1.1
60239 * Copyright(c) 2006-2007, Ext JS, LLC.
60241 * Originally Released Under LGPL - original licence link has changed is not relivant.
60244 * <script type="text/javascript">
60249 * @class Roo.XTemplate
60250 * @extends Roo.Template
60251 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60253 var t = new Roo.XTemplate(
60254 '<select name="{name}">',
60255 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60259 // then append, applying the master template values
60262 * Supported features:
60267 {a_variable} - output encoded.
60268 {a_variable.format:("Y-m-d")} - call a method on the variable
60269 {a_variable:raw} - unencoded output
60270 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60271 {a_variable:this.method_on_template(...)} - call a method on the template object.
60276 <tpl for="a_variable or condition.."></tpl>
60277 <tpl if="a_variable or condition"></tpl>
60278 <tpl exec="some javascript"></tpl>
60279 <tpl name="named_template"></tpl> (experimental)
60281 <tpl for="."></tpl> - just iterate the property..
60282 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60286 Roo.XTemplate = function()
60288 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60295 Roo.extend(Roo.XTemplate, Roo.Template, {
60298 * The various sub templates
60303 * basic tag replacing syntax
60306 * // you can fake an object call by doing this
60310 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60313 * compile the template
60315 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60318 compile: function()
60322 s = ['<tpl>', s, '</tpl>'].join('');
60324 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60325 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60326 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60327 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60328 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60333 while(true == !!(m = s.match(re))){
60334 var forMatch = m[0].match(nameRe),
60335 ifMatch = m[0].match(ifRe),
60336 execMatch = m[0].match(execRe),
60337 namedMatch = m[0].match(namedRe),
60342 name = forMatch && forMatch[1] ? forMatch[1] : '';
60345 // if - puts fn into test..
60346 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60348 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60353 // exec - calls a function... returns empty if true is returned.
60354 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60356 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60364 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60365 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60366 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60369 var uid = namedMatch ? namedMatch[1] : id;
60373 id: namedMatch ? namedMatch[1] : id,
60380 s = s.replace(m[0], '');
60382 s = s.replace(m[0], '{xtpl'+ id + '}');
60387 for(var i = tpls.length-1; i >= 0; --i){
60388 this.compileTpl(tpls[i]);
60389 this.tpls[tpls[i].id] = tpls[i];
60391 this.master = tpls[tpls.length-1];
60395 * same as applyTemplate, except it's done to one of the subTemplates
60396 * when using named templates, you can do:
60398 * var str = pl.applySubTemplate('your-name', values);
60401 * @param {Number} id of the template
60402 * @param {Object} values to apply to template
60403 * @param {Object} parent (normaly the instance of this object)
60405 applySubTemplate : function(id, values, parent)
60409 var t = this.tpls[id];
60413 if(t.test && !t.test.call(this, values, parent)){
60417 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60418 Roo.log(e.toString());
60424 if(t.exec && t.exec.call(this, values, parent)){
60428 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60429 Roo.log(e.toString());
60434 var vs = t.target ? t.target.call(this, values, parent) : values;
60435 parent = t.target ? values : parent;
60436 if(t.target && vs instanceof Array){
60438 for(var i = 0, len = vs.length; i < len; i++){
60439 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60441 return buf.join('');
60443 return t.compiled.call(this, vs, parent);
60445 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60446 Roo.log(e.toString());
60447 Roo.log(t.compiled);
60452 compileTpl : function(tpl)
60454 var fm = Roo.util.Format;
60455 var useF = this.disableFormats !== true;
60456 var sep = Roo.isGecko ? "+" : ",";
60457 var undef = function(str) {
60458 Roo.log("Property not found :" + str);
60462 var fn = function(m, name, format, args)
60464 //Roo.log(arguments);
60465 args = args ? args.replace(/\\'/g,"'") : args;
60466 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60467 if (typeof(format) == 'undefined') {
60468 format= 'htmlEncode';
60470 if (format == 'raw' ) {
60474 if(name.substr(0, 4) == 'xtpl'){
60475 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60478 // build an array of options to determine if value is undefined..
60480 // basically get 'xxxx.yyyy' then do
60481 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60482 // (function () { Roo.log("Property not found"); return ''; })() :
60487 Roo.each(name.split('.'), function(st) {
60488 lookfor += (lookfor.length ? '.': '') + st;
60489 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60492 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60495 if(format && useF){
60497 args = args ? ',' + args : "";
60499 if(format.substr(0, 5) != "this."){
60500 format = "fm." + format + '(';
60502 format = 'this.call("'+ format.substr(5) + '", ';
60506 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60510 // called with xxyx.yuu:(test,test)
60512 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60514 // raw.. - :raw modifier..
60515 return "'"+ sep + udef_st + name + ")"+sep+"'";
60519 // branched to use + in gecko and [].join() in others
60521 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60522 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60525 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60526 body.push(tpl.body.replace(/(\r\n|\n)/g,
60527 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60528 body.push("'].join('');};};");
60529 body = body.join('');
60532 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60534 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60540 applyTemplate : function(values){
60541 return this.master.compiled.call(this, values, {});
60542 //var s = this.subs;
60545 apply : function(){
60546 return this.applyTemplate.apply(this, arguments);
60551 Roo.XTemplate.from = function(el){
60552 el = Roo.getDom(el);
60553 return new Roo.XTemplate(el.value || el.innerHTML);